【问题标题】:Generate an XML doc from the DOM while skipping over certain elements在跳过某些元素时从 DOM 生成 XML 文档
【发布时间】:2014-06-11 17:18:01
【问题描述】:

我有试图从中生成 XML 文档的 HTML。我想跳过某些元素(基本上除了我的 div 之外的所有元素),为此,我编写了一个简单的 DOM 遍历函数,但我似乎陷入了无限循环。 (下面有更多详细信息。)

所以我的 HTML 看起来像这样:

<div id="browserDiv">
    <h3>Library</h3>
    <ul>
        <li>
            <div id="t-0" class="section topic" data-content="2b-2t-38-w-2c-2w-2t-33-36-3d">
                <p>Set Theory</p>
                <img class="toggle"><img class="edit">
                <img class="add-entry"><img class="delete">
                <ul>
                    <li>
                        <div id="t-0-0" class="section topic" data-content="1t-3c-2x-33-31-37">
                            <p>Axioms</p>
                            <img class="toggle"><img class="edit">
                            <img class="add-entry"><img class="delete">
                            <ul>
                                <li>
                                    <div id="t-0-0-0" class="section topic" data-content="1t-3c-2x-33-31-w-33-2u-w-2b-2t-34-2p-36-2p-38-2x-33-32">
                                        <p>Axiom of Separation</p>
                                        <img class="toggle"><img class="edit">
                                        <img class="add-entry"><img class="delete">
                                        <ul>
                                            <li>
                                                <img class="add-new">
                                            </li>
                                        </ul>
                                </li>
                                <li>
                                    <img class="add-new">
                                </li>
                        </div>
                    </li>
                    <li>
                        <img class="add-new">
                    </li>
                </ul>
            </div>
        </li>
        <li>
            <div id="t-1" class="section topic" data-content="1t-32-2p-30-3d-37-2x-37">
                <p>Analysis</p>
                <img class="toggle"><img class="edit">
                <img class="add-entry"><img class="delete">
                <ul>
                    <li>
                        <img class="add-new">
                    </li>
                </ul>
            </div>
        </li>
        <li>
            <img class="add-new">
        </li>
    </ul>
</div>

截图如下:

我正在尝试将此 html 转换为 XML 文件。但是 XML 只存储包含在 div 元素中的信息,所以当我遍历 DOM 树时,我试图跳过所有其他元素。

我打算(最终)生成的那种 XML:

<?xml version="1.0" encoding="UTF-8"?>
<library userid="095209376">
    <title>UserID095209376's Library</title>
    <topic children="yes" loadable="no">
        <id>0</id>
        <encoding>2b-2t-38-w-2c-2w-2t-33-36-3d</encoding>
        <topic children="yes" loadable="no">
            <id>0-0</id>
            <encoding>1t-3c-2x-33-31-37</encoding>
            <topic children="no" loadable="yes">
                <id>0-0-0</id>
                <encoding>1t-3c-2x-33-31-w-33-2u-w-2b-2t-34-2p-36-2p-38-2x-33-32</encoding>
            </topic>
        </topic>
    <topic children="yes" loadable="no">
        <id>1</id>
        <encoding>1t-32-2p-30-3d-37-2x-37</encoding>
    </topic>
</library>

这是我目前迭代它的方式:

(请注意,脚本标签只是为了让 SO 进行语法高亮显示。)

<script>
function saveLibrary(){

    var xmlDoc = document.implementation.createDocument('http://www.tuningcode.com', 'library');
    var rootNode = document.getElementById('browserDiv');
    console.log("rootNode here: " + rootNode);
    var libraryTree = walkLibraryTree2(rootNode, xmlDoc);
    xmlDoc.documentElement.appendChild(libraryTree);
    var oSerializer = new XMLSerializer();
    var sXML = oSerializer.serializeToString(xmlDoc);
    console.log("xmlDoc: " + xmlDoc);
    console.log(sXML);

}

function walkLibraryTree2(nodeToWalk, doc){

    var elem = doc.createElement(nodeToWalk.tagName);
    console.log(elem);
    if(nodeToWalk.hasChildNodes()){
        var ch = nodeToWalk.children;
        for(var i = 0; i < ch.length; i++){
            var theWalk = walkLibraryTree2(ch[i], doc);
            if(theWalk != null){
                if(ch[i].tagName == 'DIV'){
                    elem.appendChild(theWalk);
                } else{
                    elem = theWalk;
                }
            }
        }
        return elem;
    } else {
        return null;
    }
}

saveLibrary();
</script>

问题是当我运行它时,(编辑)它花费的时间比它应该的要长得多,并产生如下内容:

<library xmlns="http://www.tuningcode.com"><LI xmlns=""/></library>.

换句话说,它不打印任何 div,只打印一个 li 元素。我将它打印到控制台相当多,即使只有上面显示的节点数量,它也会将数千条语句打印到控制台。

问题:

我怎样才能遍历树跳过除了div 元素之外的所有元素?或者为什么上面的代码不能正常工作?

这是一个 JSFiddle:

http://jsfiddle.net/4bGjH/

【问题讨论】:

    标签: javascript html xml dom dom-traversal


    【解决方案1】:

    我认为您遇到了非常长的运行时间,因为您在 for 循环的每次迭代中调用 walkLibraryTree2 两次,从而导致指数级扩展(您的 HTML 深度为 13 级,这意味着 walkLibraryTree2被调用超过 8,000 次)。

    处理复杂问题时,最好将其分解为更小的部分。以下似乎有效:

    <script>
    function saveLibrary() {
        var xmlDoc = document.implementation.createDocument(null, 'library');
        var rootNode = document.getElementById('browserDiv');
        console.log("rootNode here: " + rootNode);
    
        appendNodes(xmlDoc.documentElement, processChildren(rootNode, xmlDoc));
    
        var oSerializer = new XMLSerializer();
        var sXML = oSerializer.serializeToString(xmlDoc);
        console.log("xmlDoc: " + xmlDoc);
        console.log(sXML);
    }
    
    // DomNode, Document -> Array[DomNode]
    function processChildren(node, doc) {
        var nodes = [],
            i;
    
        for (i = 0; i < node.childNodes.length; i += 1) {
            nodes = nodes.concat(processNode(node.childNodes[i], doc));
        }
    
        return nodes;
    }
    
    // DomNode, Array[DomNode] -> void
    function appendNodes(destNode, nodes) {
        var i;
    
        for (i = 0; i < nodes.length; i += 1) {
            destNode.appendChild(nodes[i]);
        }
    }
    
    // DomNode, Document -> Array[DomNode]
    function processNode(node, doc) {
        var children = processChildren(node, doc);
    
        if (node.tagName == "DIV") {
            return [createTopicElement(node, doc, children)];
        } else {
            return children;
        }
    }
    
    // DomNode, Document, Array[DomNode] -> DomNode
    function createTopicElement(baseNode, doc, children) {
        var el = doc.createElement("topic"),
            hasChildren = !! children.length,
            id = node.id.substring(2),
            encoding = node.getAttribute("data-content");
    
        el.setAttribute("children", hasChildren ? "yes" : "no");
        el.appendChild(createElementWithValue(doc, "id", id));
        el.appendChild(createElementWithValue(doc, "encoding", encoding));
        appendNodes(el, children);
    
        return el;
    }
    
    // Document, String, String -> DomNode
    function createElementWithValue(doc, name, value) {
        var el = doc.createElement(name);
        el.textContent = value;
        return el;
    }
    
    saveLibrary();    
    </script>
    

    这会产生 XML:

    <library>
        <topic children="yes">
            <id>0</id>
            <encoding>2b-2t-38-w-2c-2w-2t-33-36-3d</encoding>
            <topic children="yes">
                <id>0-0</id>
                <encoding>1t-3c-2x-33-31-37</encoding>
                <topic children="no">
                    <id>0-0-0</id>
                    <encoding>1t-3c-2x-33-31-w-33-2u-w-2b-2t-34-2p-36-2p-38-2x-33-32</encoding>
                </topic>
            </topic>
        </topic>
        <topic children="no">
            <id>1</id>
            <encoding>1t-32-2p-30-3d-37-2x-37</encoding>
        </topic>
    </library>
    

    我不知道您的loadable 属性是如何确定的,也不知道标题的来源,但这应该可以帮助您了解大部分情况。

    http://jsfiddle.net/Weu4A/4/

    【讨论】:

    • 非常感谢!你超出了我的要求。在我真正回应之前,我将花一些时间查看您编写的代码。我错过了你说我打电话两次的地方。对我来说,我好像叫过它一次?
    • @AmadeusDrZaius 啊,你是对的。您在之前删除的问题版本中调用了两次。
    • 感谢所有帮助。我使用您的代码重新实现了算法,使其更符合我的原始(尽管是意大利面条式)代码,以帮助我了解我的问题所在。现在工作! :) JSFiddle:jsfiddle.net/d5KgN/20 再次感谢!
    猜你喜欢
    • 1970-01-01
    • 2019-12-03
    • 2017-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多