我想问一下,将简单的html代码解析成DOM Node树的最佳方法是什么:
以下是我面临的一些限制:
<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;
发布于 2013-03-28 15:34:47
我知道它不是用C语言编写的,但是这个演示文稿可能会给你一些关于如何有效地解决这个问题的意见。
根据您的初始需求,我还用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));
https://stackoverflow.com/questions/15647971
复制相似问题