HTMLパーサー

背景:HTMLの要件は、その後、いくつかのプロセス/操作、DOMオブジェクトツリーまたはオブジェクトツリーJSに文字列をオンにする必要があります。 htmlparser ライブラリは大丈夫でしたが、属性変換にいくつかの特別なプロパティ値では動作しません。また、オープンラベルの構文``(見 構文開始タグ:WHATWG )、 `HTML属性のサポートrules`( 属性:WHATWG )といくつかのいくつかの境界のシナリオで他のライブラリの実装、(特殊な属性値および Webコンポーネント )プロセスまたは自身のライン...よく、の欠如と、それはより良いHTMLパーサの機能を持っていました。

この資料は、技術的沈殿であることが、記録処理の下で達成され、関連する要件への参照が存在してもよいです。

前処理

まず、コンテンツを見つけることを期待して一致させるために、いくつかの正規表現を定義します
CONST ltReg = / \ </グラム
のconst gtReg = / \> / gの
constのsqReg = / '/ gを
CONST qReg = / "/ gでの
CONST sqAttrReg = /(?<= \ = ')[^'] *?(? = ')/ G 
CONST qAttrReg = /(?<= \ = ")[^"] *?(?= ")/ gの
CONST qRegBk = /" / G 
CONST sqRegBk = /' / G 
CONST ltRegBk = / </ G 
CONST gtRegBk = /> /グラム
CONST attrReplaceReg = /[\:\w\d_-]*?=(["].*?["]|['].*?['])/g 
CONST attrReg = /(?<=\s)([\:\w\d\-]+\=(["'].*?["']|[\w\d]+)|\w+)/g 
のconst numReg = / ^ \ dの+ $ / 
constのclReg = / \ N / gでの
CONST SREG = / \ S /グラム
のconst spReg = / \ sの+ /グラムの
CONST tagReg = / \ <[^ \ <\>] *?\> / 
CONST startReg = / \ <[^ \ / \!]。*?\>/ 
constのendReg = /\<\/.*?\>/ 
constのcommentReg = /(?<=\<\!\-\-).*?(?=\-\-\>)/ 
CONST tagCheckReg = / [\ \ W - ](<= \ <?)+ /

一例として、単純なHTML文字列を取るために、処理ロジックを開始します。
CONST STR = ' 
<DIV ID = "コンテナ"> 
  <DIV CLASS = "テスト"データHTML = "<P>ハロー1 </ P>"> 
    <P>ハロー2 </ P> 
    の<input type = "text "値="ハロー3" > 
  </ div> 
</ div> 
`

プロパティ値のエスケープ

、開いている各タブを取って、文字列strを取得代わりに文字をエスケープするか、タグや特殊文字以内属性、文字列STR1を返します
CONST replaceAttribute =(HTML:文字列):文字列=> { 
  戻りhtml.replace(attrReplaceReg、V => { 
    戻りVの
      .replace(ltReg、 '<')
      .replace(gtReg、 '>')
      .replace(sqAttrReg、V => { 
        戻りv.replace(qReg、「" ')
      })
      .replace(qAttrReg、V => { 
        戻りv.replace(sqReg、 ''') 
      })
  })
}

結果は以下の通りであります:
; `<DIV ID = "コンテナ"> 
  <DIV CLASS = "テスト"データHTML = "<P>ハロー1 </ P>"> 
    <P>ハロー2 </ P> 
    の<input type = "text"の値= "ハロー3"> 
  </ div> 
</ div> `

コンテンツのアレイを形成します

0009ステップで文字列から切り出した要素:新しい配列ARRに配置され、(要素であるオープンラベル、コンテンツ、タグ閉鎖)。
CONST convertStringToArray =(HTML:列)=> { 
  せprivateHtml = HTML 
  せtemporaryHtml = HTML 
  CONSTのARR = [] 
  一方(privateHtml.match(tagReg)){ 
    privateHtml = temporaryHtml.replace(tagReg、(V、I)=> { 
      (I> 0){もし
        CONST値= temporaryHtml.slice(0、I)
        (value.replace(SREG、 '').LENGTH> 0){もし
          arr.push(値)
        } 
      } 
      temporaryHtml = temporaryHtml.slice(I + v.length)
      arr.push(V)
      リターン'' 
    })
  } 
  戻りARR 
}

結果は以下の通りであります:
 [ "<DIV ID =" コンテナ ">"、 "<DIV CLASS =" テスト "データHTML = "<P>ハロー1 </ P>">"、 "<P>"、 "ハロー2"、 " </ P> " "<入力タイプ=" テキスト" 値= "ハロー3">」、 "</ div>"、 "</ div>"]

生成オブジェクトツリー

ARRのステップは、処理対象のツリーに、循環上に形成されました
//単一ラベルセットの
VAR = singleTags [ 
  'IMG'、
  'INPUT'、
  'BR'、
  'HR'、
  'メタ'、
  'リンク'、
  'PARAM'、
  'ベース'、
  'BASEFONT'、
  '地域'、
  "ソース「
  『トラック』、
  『埋め込み』
] 
// DomUtilオブジェクトは、関数又はnodejsに従ってJS / DOMオブジェクト・ブラウザ環境を生成することであることを特徴とする請求
VAR makeUpTree =関数(ARR){ 
  VARルートDomUtil =(」コンテナ「)
  VAR = 0ディープ
  parentElements = VAR [ルート] 
  arr.forEach(関数(I){ 
    VAR parentElement = parentElements [parentElements。長さ- 1] 
    IF(parentElement){ 
      VAR inlineI = toOneLine(I)
      //オープンラベル治療、新しいオープンラベルタグ
      (startReg.test(inlineI)){IF 
        ディープ++の
        VARタグ名= i.match(tagCheckReg)
        IF(!tagNameを){ 
          スローエラー( 'ラベル指定エラー')
        } 
        1 = DomUtil(tagNameを[0]) - VARのELEMENT 
        VAR ATTRS = matchAttr (I)
        attrs.forEach(関数(ATTR){ 
          IF(ELEMENT - 1){ 
            element_1.setAttribute(ATTR [0]、ATTRの[1])
          } 
        })
        parentElement.appendChild(ELEMENT - 1)
        //単一ラベルの治療、deep--、閉フラグを完了
        IF(
          singleTags.indexOf(tagNameを[0])> -1 || 
          i.charAt(i.length - 2)=== '/' 
        ){ 
          deep--
        }他{ 
          parentElements.push(element_1)
        } 
      } 
      //闭合标签处理
      他IF(endReg.test(inlineI)){ 
        deep-- 
        parentElements.pop()
      }そうであれば(commentReg.test(inlineI)){ 
        VAR matchValue = i.match(commentReg)
        var注釈= matchValue?matchValue [0]: ' 
        深い++の
        VAR要素= DomUtil( 'コメント'、コメント)
        parentElement.appendChild(要素)
        deep-- 
      }他{ 
        深い++用
        のvarのTextElement = DomUtil( 'テキスト'、I)
        parentElement.appendChild(のTextElement)
        ディープ- 
      }
    } 
  }) ディープIF <0){ 
    スローエラー( '過剰ラベルの閉鎖存在')
  }他IF(ディープ> 0){ 
    スローエラー( '過剰オープンラベルの存在')
  } 
  戻りroot.children 
}

結果は以下の通りであります:
[ 
  { 
    ATTRS:{ 
      ID: 'コンテナー' 
    }、
    parentElement:[DOMELEMENT]、
    子供:[ 
      { 
        ATTRS:{ 
          クラス: 'テスト'、
          'データHTML': '<P>ハロー1 </ P>' 
        }、
        parentElement:[DOMELEMENT]、
        子供:[ 
          { 
            ATTRS:{}、
            parentElement:[DOMELEMENT]、
            子供:[ 
              { 
                ATTRS:{}、
                parentElement:[DOMELEMENT]、
                子供:[]、
                tagNameを: 'テキスト'、
                データ'こんにちは2'
              } 
            ]、
            tagNameを'P' 
          }、
          { 
            ATTRS:{ 
              タイプ: 'テキスト'、
              値'ハロー3' 
            }、
            parentElement:[DOMELEMENT]、
            子供:[]、
            tagNameを'入力' 
          } 
        ]、
        tagNameを' DIV」
      } 
    ]、
    tagNameを: 'DIV' 
  } 
]

組み合わせ

上記の3つのステップの組み合わせ
CONSTパーサー=(HTML:列)=> { 
  CONST htmlAfterAttrsReplace = replaceAttribute(HTML)
  CONSTのStringArray = convertStringToArray(htmlAfterAttrsReplace)
  CONST domTree = makeUpTree(のStringArray)
  domTreeを返します
}

テスト

最後に、波をテストしてください。

チュウヤ/淘宝網/百度/ JD / TXホームページやニュースページは、HTMLが多く、HTML文字に比べて `100ms`以内に完了基本的な実行の波、そしておそらく数千人のような数のDOMを、テストコピーされますATTRSオブジェクトと文字列のオブジェクトの属性は、まだ対応します。
 
EMM ...かなり、との最初の行。

遂に

コードを書くには十分満足して何...

あなたが私たちのチームに興味がある場合は、参加することを歓迎し、あなたの参加を楽しみにして、あなたは私のメール[email protected]を提供することができます!

より多くのジョブを表示することができ チュウヤ動員を

おすすめ

転載: www.cnblogs.com/ys-ys/p/11668981.html