7

次のような単純な html コードを DOM ノード ツリーに解析する最良の方法は何ですか?

例の木

ここに私が直面しているいくつかの制約があります:

  • HTMLコードにはペアタグのみがあり、属性はなく、スペースを無視する必要があります
  • 、など<p>のタグの間にテキストを含めることができます。<h1><a>
  • ライブラリが使えない

私は正規表現について考えていましたが、試したことはありませんでした..何かアイデアはありますか?

ツリー内のすべてのノードは次の構造体です。

  typedef struct tag
  {
      struct tag* parent;
      struct tag* nextSibling;
      struct tag* previousSibling;
      struct tag* firstChild;
      struct tag* lastChild;     
      char* name;
      char* text;     
  }node;
4

1 に答える 1

2

C で書かれていないことはわかっていますが、そのプレゼンテーションは、問題に効率的に取り組む方法についての情報を提供してくれるかもしれません。

https://web.archive.org/web/20120115060003/http://cuddle.googlecode.com/hg/talk/lex.html#landing-slide

また、最初の要件に基づいて、JavaScript で非常に単純なパーサーの例を作成しました (これも C ではありませんが、JS も知っていることを願っています)。これは、属性を解析せず、自己終了タグや他の多くのものを処理しないことを意味します。 HTML仕様に従って処理する必要があります。次の形式で解析ツリーが生成されます。

{
    cn: [{
        tag: 'html',
        cn: [{
            tag: 'body',
            cn: [
                { tag: 'h1', cn: ['test'] },
                ' some text ',
                ...
            ]
        }] 
    }]
}

コードとフィドルは次のとおりです。http://jsfiddle.net/LUpyZ/3/

空白は無視されず、テキスト ノードに取り込まれることに注意してください。

var html = '<html><body><h1>test</h1> some text <div> <p>text</p></div></body></html>';

var parseHTML = (function () {
    var nodesStack = [],
        i = 0,
        len = html.length,
        stateFn = parseText,
        parseTree = { cn: [] },
        alphaNumRx = /\w/,
        currentNode = parseTree,
        text = '',
        tag = '',
        newNode;

    function parseTag(token) {
        if (token === '/') {
            return parseCloseTag;
        }

        i--; //backtrack to first tag character
        return parseOpenTag;
    }

    function parseCloseTag(token) {
        if (token === '>') {
            if (currentNode.tag !== tag) {
                throw 'Wrong closed tag at char ' + i;
            }

            tag = '';

            nodesStack.pop();

            currentNode = currentNode.parentNode;

            return parseText;            
        }

        assertValidTagNameChar(token);

        tag += token;

        return parseCloseTag;
    }

    function parseOpenTag(token) {
        if (token === '>') {
            currentNode.cn.push(newNode = { tag: tag, parentNode: currentNode,  cn: []});
            nodesStack.push(currentNode = newNode);

            tag = '';

            return parseText;
        }

        assertValidTagNameChar(token);

        tag += token;

        return parseOpenTag;
    }

    function parseText(token) {
        if (token === '<') {

            if (text) {
                currentNode.cn.push(text);
                text = '';
            }

            return parseTag;
        }

        text += token;

        return parseText;
    }

    function assertValidTagNameChar(c) {
        if (!alphaNumRx.test(c)) {
            throw 'Invalid tag name char at ' + i;
        }
    }

    return function (html) {
        for (; i < len; i++) {
            stateFn = stateFn(html[i]);
        }

        if (currentNode = nodesStack.pop()) {
            throw 'Unbalanced tags: ' + currentNode.tag + ' is never closed.';
        }

        return parseTree;
    };
})();

console.log(parseHTML(html));
于 2013-03-28T07:34:47.107 に答える