JS로 HTML 문자열 구문 분석


258

솔루션을 검색했지만 관련성이 없으므로 여기 내 문제가 있습니다.

HTML 텍스트가 포함 된 문자열을 구문 분석하고 싶습니다. JavaScript로하고 싶습니다.

이 라이브러리를 사용해 보았지만 문자열이 아닌 현재 페이지의 HTML을 구문 분석하는 것 같습니다. 아래 코드를 시도하면 페이지 제목이 변경되므로

var parser = new HTMLtoDOM("<html><head><title>titleTest</title></head><body><a href='test0'>test01</a><a href='test1'>test02</a><a href='test2'>test03</a></body></html>", document);

내 목표는 문자열처럼 읽은 HTML 외부 페이지에서 링크를 추출하는 것입니다.

API를 알고 있습니까?



1
연결된 복제본의 메서드는 지정된 문자열에서 HTML 문서를 만듭니다. 그런 다음 doc.getElementsByTagName('a')링크 (또는 doc.links) 를 읽는 데 사용할 수 있습니다 .
Rob W

React.js와 같은 프레임 워크를 사용하는 경우 다음과 같은 프레임 워크에 특정한 방법을 사용할 수 있습니다. stackoverflow.com/questions/23616226/…
Mike Lyons

이것이 귀하의 질문에 대답합니까? 텍스트 JavaScript에서 HTML 제거
Leif Arne Storset

답변:


373

더미 DOM 요소를 만들고 문자열을 추가하십시오. 그런 다음 DOM 요소처럼 조작 할 수 있습니다.

var el = document.createElement( 'html' );
el.innerHTML = "<html><head><title>titleTest</title></head><body><a href='test0'>test01</a><a href='test1'>test02</a><a href='test2'>test03</a></body></html>";

el.getElementsByTagName( 'a' ); // Live NodeList of your anchor elements

편집 : 팬을 기쁘게하기 위해 jQuery 답변을 추가하십시오!

var el = $( '<div></div>' );
el.html("<html><head><title>titleTest</title></head><body><a href='test0'>test01</a><a href='test1'>test02</a><a href='test2'>test03</a></body></html>");

$('a', el) // All the anchor elements

9
참고 사항 :이 솔루션을 사용하여 "alert (el.innerHTML)"을 수행하면 <html>, <body> 및 <head> 태그가 손실됩니다 ...
stage

2
문제 : <frame> 태그에서 링크를 가져와야합니다. 그러나이 솔루션을 사용하면 프레임 태그가 삭제됩니다 ...
stage

3
@stage 파티에 약간 늦었지만 및 태그 document.createElement('html');를 보존하는 데 사용할 수 있어야 합니다. <head><body>
omninonsense

3
html 요소 안에 html 요소를 넣은 것 같습니다
symbiont

6
나는 최고의 대답으로 우려된다. parse()아래 의 솔루션은 더 재사용 가능하고 우아합니다.
Justin

232

아주 간단합니다 :

var parser = new DOMParser();
var htmlDoc = parser.parseFromString(txt, 'text/html');
// do whatever you want with htmlDoc.getElementsByTagName('a');

MDN에 따르면 크롬 에서이 작업을 수행하려면 다음과 같이 XML로 구문 분석해야합니다.

var parser = new DOMParser();
var htmlDoc = parser.parseFromString(txt, 'text/xml');
// do whatever you want with htmlDoc.getElementsByTagName('a');

현재 웹킷에서 지원되지 않으며 Florian의 답변을 따라야하며 대부분의 경우 모바일 브라우저에서 작동하지 않습니다.

편집 : 이제 널리 지원


35
2016 년 DOMParser가 이제 널리 지원된다는 점에 주목할 가치가 있습니다. caniuse.com/#feat=xml-serializer
11

5
문서가 상속에 의해 작성되는 때문에 생성 된 문서의 모든 상대 링크가 깨진 지적 가치 documentURLwindow문자열의 URL에서, 어떤 가능성이 다릅니다.
17 초에 ceving

2
당신이해야한다고 지적 가치 호출 new DOMParser하면 다음 스크립트의 나머지 부분에 걸쳐 같은 개체를 다시 사용합니다.
잭 지핀

1
parse()아래 의 솔루션은 재사용 성이 높고 HTML에 따라 다릅니다. 그러나 XML 문서가 필요한 경우에 좋습니다.
Justin

이 구문 분석 된 웹 페이지를 대화 상자 나 다른 곳에 표시하려면 어떻게해야합니까? 나는에 대한 해결책을 찾을 수 없습니다 그
Shariq Musharaf

18

편집 : 아래 솔루션은 html, 헤드 및 바디가 제거되므로 HTML "조각"에만 해당됩니다. 이 질문에 대한 해결책은 DOMParser의 parseFromString () 메소드라고 생각합니다.


HTML 조각의 경우 여기에 나열된 솔루션은 대부분의 HTML에서 작동하지만 특정 경우에는 작동하지 않습니다.

예를 들어 파싱을 시도하십시오 <td>Test</td>. 이것은 div.innerHTML 솔루션이나 DOMParser.prototype.parseFromString 또는 range.createContextualFragment 솔루션에서 작동하지 않습니다. td 태그가 사라지고 텍스트 만 남습니다.

jQuery 만 해당 사례를 잘 처리합니다.

향후 솔루션 (MS Edge 13+)은 템플릿 태그를 사용하는 것입니다.

function parseHTML(html) {
    var t = document.createElement('template');
    t.innerHTML = html;
    return t.content.cloneNode(true);
}

var documentFragment = parseHTML('<td>Test</td>');

이전 버전의 브라우저를 들어 내가 독립적 인 요점으로 jQuery의 parseHTML () 메소드를 추출한 - https://gist.github.com/Munawwar/6e6362dbdf77c7865a99


구형 브라우저에서도 작동하는 호환 코드를 작성하려면 <template>태그를 polyfill 할 수 있습니다 . 폴리 필해야 하는 사용자 정의 요소에 따라 다릅니다 . 실제로 webcomponents.js 를 사용 하여 사용자 정의 요소, 템플릿, 그림자 돔, 약속 및 기타 몇 가지를 한꺼번에 폴리 필 할 수 있습니다 .
Jeff Laughlin

12
var doc = new DOMParser().parseFromString(html, "text/html");
var links = doc.querySelectorAll("a");

4
왜 접두사 $입니까? 에서 언급 한 바와 같이 또한, 연결 중복 , text/html아주 잘 지원하고, polyfill을 사용하여 구현 될 필요가 없습니다.
Rob W

1
이 줄을 프로젝트에서 복사했습니다. 라이브러리가 아닌 자바 스크립트 응용 프로그램에서 변수 앞에 $를 붙이는 데 사용됩니다. 도서관과의 충돌을 피하는 것입니다. 거의 모든 변수의 범위가 정해져 있기 때문에 유용하지는 않지만 유용했습니다. 변수를 쉽게 식별하는 데 도움이 될 수도 있습니다.
Mathieu

1
슬프게도 크롬에서 DOMParser작동하지 않는 이 MDN 페이지 는 해결 방법을 제공합니다. text/html
Jokester

보안 정보 : 브라우저 컨텍스트없이 실행되므로 스크립트가 실행되지 않습니다. 신뢰할 수없는 입력에 적합해야합니다.
Leif Arne Storset

6

Chrome 및 Firefox에서 HTML을 구문 분석하는 가장 빠른 방법은 Range # createContextualFragment입니다.

var range = document.createRange();
range.selectNode(document.body); // required in Safari
var fragment = range.createContextualFragment('<h1>html...</h1>');
var firstNode = fragment.firstChild;

가능한 경우 createContextualFragment를 사용하고 그렇지 않으면 innerHTML로 대체되는 도우미 함수를 만드는 것이 좋습니다.

벤치 마크 : http://jsperf.com/domparser-vs-createelement-innerhtml/3


(간단한) 같은 것을 참고 innerHTML, 이것이 실행합니다 <img>'들 onerror.
Ry-

이 문제는 '<td> test </ td>'와 같은 HTML이 document.body 컨텍스트에서 td를 무시하고 ( 'test'텍스트 노드 만 작성) OTOH (템플릿 엔진에서 내부적으로 사용 된 경우) 올바른 컨텍스트를 사용할 수 있습니다.
Munawwar

또한 BTW, IE 11은 createContextualFragment를 지원합니다.
Munawwar

하지 크롬이나 파이어 폭스 - 질문은 JS와 구문 분석하는 방법이었다
sea26.2

보안 정보 : 입력에서 모든 스크립트를 실행하므로 신뢰할 수없는 입력에 적합하지 않습니다.
Leif Arne Storset

6

다음 함수 parseHTML는 다음 중 하나를 반환합니다.

  • Document파일이 doctype으로 시작 하는 경우

  • DocumentFragment파일은 문서 타입으로 시작되지 않을 때.


코드 :

function parseHTML(markup) {
    if (markup.toLowerCase().trim().indexOf('<!doctype') === 0) {
        var doc = document.implementation.createHTMLDocument("");
        doc.documentElement.innerHTML = markup;
        return doc;
    } else if ('content' in document.createElement('template')) {
       // Template tag exists!
       var el = document.createElement('template');
       el.innerHTML = markup;
       return el.content;
    } else {
       // Template tag doesn't exist!
       var docfrag = document.createDocumentFragment();
       var el = document.createElement('body');
       el.innerHTML = markup;
       for (i = 0; 0 < el.childNodes.length;) {
           docfrag.appendChild(el.childNodes[i]);
       }
       return docfrag;
    }
}

사용하는 방법 :

var links = parseHTML('<!doctype html><html><head></head><body><a>Link 1</a><a>Link 2</a></body></html>').getElementsByTagName('a');

IE8에서 작동하지 못했습니다. 함수의 첫 번째 줄에 대해 "개체가이 속성이나 메서드를 지원하지 않습니다"라는 오류가 발생합니다. 나는 createHTMLDocument 함수가 존재하지 않는다고 생각한다
Sebastian Carroll

사용 사례는 정확히 무엇입니까? HTML을 구문 분석하고 HTML을 문서 본문에 사용하려는 경우 다음을 수행 할 수 있습니다. (1) var div = document.createElement ( "DIV"); (2) div.innerHTML = 마크 업; (3) 결과 = div.childNodes; --- 이것은 자식 노드 모음을 제공하며 IE8뿐만 아니라 IE6-7에서도 작동해야합니다.
John Slegers

대체 옵션에 감사드립니다. 다시 시도해야하는 경우 시도해 보겠습니다. 지금까지는 위의 JQuery 솔루션을 사용했습니다.
Sebastian Carroll

@SebastianCarroll IE8은 trim문자열 에서 메소드를 지원하지 않습니다 . stackoverflow.com/q/2308134/3210837을 참조하십시오 .
칫솔

2
@ 칫솔 : IE8 지원은 2017 년 새벽에도 여전히 관련이 있습니까?
John Slegers

4

jQuery를 사용할 수 있다면 HTML 문자열에서 분리 된 DOM 요소를 만드는 훌륭한 기능이 있습니다. 그런 다음 일반적인 수단을 통해 쿼리 할 수 ​​있습니다 (예 :

var html = "<html><head><title>titleTest</title></head><body><a href='test0'>test01</a><a href='test1'>test02</a><a href='test2'>test03</a></body></html>";
var anchors = $('<div/>').append(html).find('a').get();

편집-방금 @Florian의 답변을 보았습니다. 이것은 기본적으로 그가 말한 것과 동일하지만 jQuery를 사용합니다.


4
const parse = Range.prototype.createContextualFragment.bind(document.createRange());

document.body.appendChild( parse('<p><strong>Today is:</strong></p>') ),
document.body.appendChild( parse(`<p style="background: #eee">${new Date()}</p>`) );


Node부모 Node(의 시작) 내의 유효한 자식 만 Range구문 분석됩니다. 그렇지 않으면 예기치 않은 결과가 발생할 수 있습니다.

// <body> is "parent" Node, start of Range
const parseRange = document.createRange();
const parse = Range.prototype.createContextualFragment.bind(parseRange);

// Returns Text "1 2" because td, tr, tbody are not valid children of <body>
parse('<td>1</td> <td>2</td>');
parse('<tr><td>1</td> <td>2</td></tr>');
parse('<tbody><tr><td>1</td> <td>2</td></tr></tbody>');

// Returns <table>, which is a valid child of <body>
parse('<table> <td>1</td> <td>2</td> </table>');
parse('<table> <tr> <td>1</td> <td>2</td> </tr> </table>');
parse('<table> <tbody> <td>1</td> <td>2</td> </tbody> </table>');

// <tr> is parent Node, start of Range
parseRange.setStart(document.createElement('tr'), 0);

// Returns [<td>, <td>] element array
parse('<td>1</td> <td>2</td>');
parse('<tr> <td>1</td> <td>2</td> </tr>');
parse('<tbody> <td>1</td> <td>2</td> </tbody>');
parse('<table> <td>1</td> <td>2</td> </table>');

보안 정보 : 입력에서 모든 스크립트를 실행하므로 신뢰할 수없는 입력에 적합하지 않습니다.
Leif Arne Storset

0

이 간단한 코드를 사용하면 다음을 수행 할 수 있습니다.

let el = $('<div></div>');
$(document.body).append(el);
el.html(`<html><head><title>titleTest</title></head><body><a href='test0'>test01</a><a href='test1'>test02</a><a href='test2'>test03</a></body></html>`);
console.log(el.find('a[href="test0"]'));
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.