programing

HTML을 JSON에 매핑

bestprogram 2023. 3. 18. 09:29

HTML을 JSON에 매핑

HTML을 구조 그대로 JSON에 매핑하려고 합니다.이 기능을 제공하는 도서관이 있나요? 아니면 제가 직접 써야 하나요?html2json 라이브러리가 없는 경우 xml2json 라이브러리를 사용할 수 있습니다.어쨌든 html은 xml의 변형일 뿐입니다.

업데이트: 예를 들어 보겠습니다.제가 하려는 것은 다음과 같습니다.html 문자열을 구문 분석합니다.

<div>
  <span>text</span>Text2
</div>

다음과 같은 json 객체로 변환합니다.

{
  "type" : "div",
  "content" : [
    {
      "type" : "span",
      "content" : [
        "Text2"
      ]
    },
    "Text2"
  ]
}

주의: 태그를 눈치채지 못한 경우 Javascript에서 해결책을 찾고 있습니다.

이 기능은 고객이 원하는 대로 작성했습니다.실행해 보고, 문제가 있는 경우는 알려 주세요.

// Test with an element.
var initElement = document.getElementsByTagName("html")[0];
var json = mapDOM(initElement, true);
console.log(json);

// Test with a string.
initElement = "<div><span>text</span>Text2</div>";
json = mapDOM(initElement, true);
console.log(json);

function mapDOM(element, json) {
    var treeObject = {};
    
    // If string convert to document Node
    if (typeof element === "string") {
        if (window.DOMParser) {
              parser = new DOMParser();
              docNode = parser.parseFromString(element,"text/xml");
        } else { // Microsoft strikes again
              docNode = new ActiveXObject("Microsoft.XMLDOM");
              docNode.async = false;
              docNode.loadXML(element); 
        } 
        element = docNode.firstChild;
    }
    
    //Recursively loop through DOM elements and assign properties to object
    function treeHTML(element, object) {
        object["type"] = element.nodeName;
        var nodeList = element.childNodes;
        if (nodeList != null) {
            if (nodeList.length) {
                object["content"] = [];
                for (var i = 0; i < nodeList.length; i++) {
                    if (nodeList[i].nodeType == 3) {
                        object["content"].push(nodeList[i].nodeValue);
                    } else {
                        object["content"].push({});
                        treeHTML(nodeList[i], object["content"][object["content"].length -1]);
                    }
                }
            }
        }
        if (element.attributes != null) {
            if (element.attributes.length) {
                object["attributes"] = {};
                for (var i = 0; i < element.attributes.length; i++) {
                    object["attributes"][element.attributes[i].nodeName] = element.attributes[i].nodeValue;
                }
            }
        }
    }
    treeHTML(element, treeObject);
    
    return (json) ? JSON.stringify(treeObject) : treeObject;
}

작업 예: http://jsfiddle.net/JUSsf/ (Chrome에서 테스트 완료, 완전한 브라우저 지원은 보증할 수 없습니다.이것을 테스트해 주세요.)

구조를 HTML을합니다.JSON.stringify()최신 브라우저(IE8+, Firefox 3+ 등)에 포함되어 있습니다.구식 브라우저를 지원하려면 json2.js를 포함할 수 있습니다.

DOM 요소 중 할 수 .stringXHTML」이 「XHTML」(「XHTML」, 「XHTML」)하고 있는지 하지 않습니다).DOMParser() 상황에서 in will 、 、 、 、 will will will will will will will will will로 되어 있기 합니다."text/xml"에러 처리를 하지 않는지도 모릅니다.도 ★★★★★★★★★★★★★★★."text/html"

를 쉽게 수 .elementJSON을 사용하다

htlm2json

복잡한 HTML 문서를 표현하는 것은 어렵고, 코너 케이스로 가득합니다만, 이러한 종류의 프로그램을 시작하는 방법을 보여 주는 몇 가지 기술을 공유하고 싶습니다. 추상화를 .toJSON

래,,html2json는 HTML 노드를 입력으로 사용하고 그 결과 JSON 문자열을 반환하는 작은 함수입니다.특히 코드가 매우 평평하지만 여전히 깊이 중첩된 트리 구조를 구축할 수 있는 충분한 기능을 갖추고 있어 복잡성이 거의 없는 것이 가능합니다.

const Elem = e => ({
  tagName: 
    e.tagName,
  textContent:
    e.textContent,
  attributes:
    Array.from(e.attributes, ({name, value}) => [name, value]),
  children:
    Array.from(e.children, Elem)
})

const html2json = e =>
  JSON.stringify(Elem(e), null, '  ')
  
console.log(html2json(document.querySelector('main')))
<main>
  <h1 class="mainHeading">Some heading</h1>
  <ul id="menu">
    <li><a href="/a">a</a></li>
    <li><a href="/b">b</a></li>
    <li><a href="/c">c</a></li>
  </ul>
  <p>some text</p>
</main>

예에서는 " " " 입니다.textContent간간도도도도도도 또 데이터 즉 데이터 생성자를 합니다.TextElemchildNodes)children를 에 하도록 선택합니다.e.nodeType– 이를 통해 필요한 것에 조금 더 다가갈 수 있습니다.

const TextElem = e => ({
  type:
    'TextElem',
  textContent:
    e.textContent
})

const Elem = e => ({
  type:
    'Elem',
  tagName: 
    e.tagName,
  attributes:
    Array.from(e.attributes, ({name, value}) => [name, value]),
  children:
    Array.from(e.childNodes, fromNode)
})

const fromNode = e => {
  switch (e?.nodeType) {
    case 1: return Elem(e)
    case 3: return TextElem(e)
    default: throw Error(`unsupported nodeType: ${e.nodeType}`) 
  }
}

const html2json = e =>
  JSON.stringify(Elem(e), null, '  ')
  
console.log(html2json(document.querySelector('main')))
<main>
  <h1 class="mainHeading">Some heading</h1>
  <ul id="menu">
    <li><a href="/a">a</a></li>
    <li><a href="/b">b</a></li>
    <li><a href="/c">c</a></li>
  </ul>
  <p>some text</p>
</main>

어쨌든, 그 문제에 대한 두 번의 반복입니다.물론 각 케이스에 대응해야 합니다만, 이 어프로치의 장점은 HTML을 JSON에서 원하는 대로 인코딩할 수 있는 유연성이 매우 뛰어나고, 복잡함도 크지 않다는 것입니다.

제 경험상 이 기술을 계속 반복하면 정말 좋은 결과를 얻을 수 있습니다.이 답변에 흥미가 있는 분이 계시다면 자세히 설명해 주세요^_^

관련:JavaScript를 사용한 재귀 메서드: JSON.stringify 자체 버전 구축


json2의 출력

위에서는 HTML에서 JSON으로 넘어갔고, 이제 JSON에서 HTML로 넘어갈 수 있게 되었습니다.데이터를 잃지 않고 두 가지 데이터 유형을 변환할 수 있는 것을 동형이라고 합니다.여기서 기본적으로 하고 있는 것은 위의 각 함수의 역수를 쓰는 것입니다.

const HtmlNode = (tagName, attributes = [], children = []) => {
  const e = document.createElement(tagName)
  for (const [k, v] of attributes) e.setAttribute(k, v)
  for (const child of children) e.appendChild(toNode(child))
  return e
}

const TextNode = (text) => {
  return document.createTextNode(text)
}
  
const toNode = t => {
  switch (t?.type) {
    case "Elem": return HtmlNode(t.tagName, t.attributes, t.children)
    case "TextElem": return TextNode(t.textContent)
    default: throw Error("unsupported type: " + t.type)
  }
}

const json2html = json =>
  toNode(JSON.parse(json))

const parsedJson =
  {"type":"Elem","tagName":"MAIN","attributes":[],"children":[{"type":"TextElem","textContent":"\n  "},{"type":"Elem","tagName":"H1","attributes":[["class","mainHeading"]],"children":[{"type":"TextElem","textContent":"Some heading"}]},{"type":"TextElem","textContent":"\n  "},{"type":"Elem","tagName":"UL","attributes":[["id","menu"]],"children":[{"type":"TextElem","textContent":"\n    "},{"type":"Elem","tagName":"LI","attributes":[],"children":[{"type":"Elem","tagName":"A","attributes":[["href","/a"]],"children":[{"type":"TextElem","textContent":"a"}]}]},{"type":"TextElem","textContent":"\n    "},{"type":"Elem","tagName":"LI","attributes":[],"children":[{"type":"Elem","tagName":"A","attributes":[["href","/b"]],"children":[{"type":"TextElem","textContent":"b"}]}]},{"type":"TextElem","textContent":"\n    "},{"type":"Elem","tagName":"LI","attributes":[],"children":[{"type":"Elem","tagName":"A","attributes":[["href","/c"]],"children":[{"type":"TextElem","textContent":"c"}]}]},{"type":"TextElem","textContent":"\n  "}]},{"type":"TextElem","textContent":"\n  "},{"type":"Elem","tagName":"P","attributes":[],"children":[{"type":"TextElem","textContent":"some text"}]},{"type":"TextElem","textContent":"\n"}]}

document.body.appendChild(toNode(parsedJson))

예전에 ExtJs의 풀 프레임워크 자체가 JSON이라는 것을 읽었을 때 링크를 거의 받지 못했습니다.

http://www.thomasfrank.se/xml_to_json.html

http://camel.apache.org/xmljson.html

온라인 XML-JSON 변환기:http://jsontoxml.utilities-online.info/

업데이트 BTW, 문제가 된 JSON을 가져오려면 HTML에도 이와 같은 유형 및 콘텐츠 태그가 있어야 합니다.또는 JSON 변환 실행 중에 이러한 요소를 추가하기 위해 xslt 변환을 사용해야 합니다.

<?xml version="1.0" encoding="UTF-8" ?>
<type>div</type>
<content>
    <type>span</type>
    <content>Text2</content>
</content>
<content>Text2</content>

HTML을 다음과 같이 JSON으로 표현해야 하는 유사한 문제가 있었습니다.

  • HTML 을 합니다.string
  • HTML 요소의 경우 다음 배열을 사용합니다.
    • 요소의 (태그) 이름
    • 객체, 속성 키에 속성 값 매핑
    • 하위 노드의 (인된) 목록

예:

<div>
  <span>text</span>Text2
</div>

된다

[
   'div',
   {},
   ['span', {}, 'text'],
   'Text2'
]

DOM Element를 이러한 JS 구조로 변환하는 기능을 작성했습니다.이 기능은 이 답변의 끝에 있습니다.함수는 Typescript에 기재되어 있습니다.타입스크립트 플레이그라운드를 사용하여 클린 JavaScript로 변환할 수 있습니다.


게다가 html 문자열을 DOM 에 해석할 필요가 있는 경우는, 에 할당합니다..innerHtml:

let element = document.createElement('div')
element.innerHtml = htmlString

또, 이것은 일반적인 지식입니다만, JSON 문자열의 출력이 필요한 경우는, 을 사용해 주세요.


/**
 * A NodeDescriptor stands for either an (HTML) Element, or for a text node
 */
export type NodeDescriptor = ElementDescriptor | string

/**
 * Array representing an HTML Element. It consists of:
 *
 * - The (tag) name of the element
 * - An object, mapping attribute keys to attribute values
 * - The (inlined) list of children nodes
 */
export type ElementDescriptor = [
   string,
   Record<string, string>,
   ...NodeDescriptor[]
]

export let htmlToJs = (element: Element, trim = true): ElementDescriptor => {
   let convertElement = (element: Element): ElementDescriptor => {
      let attributeObject: Record<string, string> = {}
      for (let { name, value } of element.attributes) {
         attributeObject[name] = value
      }

      let childArray: NodeDescriptor[] = []
      for (let node of element.childNodes) {
         let converter = htmlToJsDispatch[node.nodeType]
         if (converter) {
            let descriptor = converter(node as any)
            let skip = false

            if (trim && typeof descriptor === 'string') {
               descriptor = descriptor.trim()
               if (descriptor === '') skip = true
            }

            if (!skip) childArray.push(descriptor)
         }
      }

      return [element.tagName.toLowerCase(), attributeObject, ...childArray]
   }

   let htmlToJsDispatch = {
      [element.ELEMENT_NODE]: convertElement,
      [element.TEXT_NODE]: (node: Text): string => node.data,
   }

   return convertElement(element)
}

@Gorge Reith 감사합니다.@George Reith가 제공한 솔루션을 바탕으로 (1) 각각의 'hrefs' 링크를 더욱 분리하는 기능, (2) 속성을 키로 사용하는 기능(속성이 더 설명적이기 때문에), (3) Chrome을 사용하지 않고 Node.j 내에서 사용할 수 있는 기능.

const jsdom = require('jsdom') // npm install jsdom provides in-built Window.js without needing Chrome


// Function to map HTML DOM attributes to inner text and hrefs
function mapDOM(html_string, json) {
    treeObject = {}

    // IMPT: use jsdom because of in-built Window.js
    // DOMParser() does not provide client-side window for element access if coding in Nodejs
    dom = new jsdom.JSDOM(html_string)
    document = dom.window.document
    element = document.firstChild

    // Recursively loop through DOM elements and assign attributes to inner text object
    // Why attributes instead of elements? 1. attributes more descriptive, 2. usually important and lesser
    function treeHTML(element, object) {
        var nodeList = element.childNodes;
        if (nodeList != null) {
           if (nodeList.length) {
               object[element.nodeName] = []  // IMPT: empty [] array for non-text recursivable elements (see below)
               for (var i = 0; i < nodeList.length; i++) {
                   // if final text
                   if (nodeList[i].nodeType == 3) {
                       if (element.attributes != null) {
                           for (var j = 0; j < element.attributes.length; j++) {
                                if (element.attributes[j].nodeValue !== '' && 
                                    nodeList[i].nodeValue !== '') {
                                    if (element.attributes[j].name === 'href') { // separate href
                                        object[element.attributes[j].name] = element.attributes[j].nodeValue;
                                    } else {
                                        object[element.attributes[j].nodeValue] = nodeList[i].nodeValue;
                                    }

                                }
                           }
                       }
                   // else if non-text then recurse on recursivable elements
                   } else {
                       object[element.nodeName].push({}); // if non-text push {} into empty [] array
                       treeHTML(nodeList[i], object[element.nodeName][object[element.nodeName].length -1]);
                   }
               }
           }
        }
    }
    treeHTML(element, treeObject);

    return (json) ? JSON.stringify(treeObject) : treeObject;
}

언급URL : https://stackoverflow.com/questions/12980648/map-html-to-json