将XML /给定输入转换为有效的有序列表

时间:2014-10-13 13:18:39

标签: jquery html xml regex

这可能需要考虑很多,但我尽我所能尽力解释。

我有一个输入/上传字段,用户可以在其中提供XML文件。该文件如下所示。

<node begin="0" cat="smain" end="10" id="1" rel="--">
    <node begin="0" cat="np" end="5" id="2" rel="su">
        <node begin="0" end="1" id="3" lemma="de" lwtype="bep" naamval="stan" npagr="rest" pos="det" postag="LID(bep,stan,rest)" pt="lid" rel="det" root="de" word="De" />
        <node begin="1" end="2" genus="zijd" getal="ev" graad="basis" id="4" lemma="helft" naamval="stan" ntype="soort" pos="noun" postag="N(soort,ev,basis,zijd,stan)" pt="n" rel="hd" root="helft" word="helft" />
        <node begin="2" cat="pp" end="5" id="5" rel="mod">
            <node begin="2" end="3" id="6" lemma="van" pos="prep" postag="VZ(init)" pt="vz" rel="hd" root="van" vztype="init" word="van" />
            <node begin="3" cat="np" end="5" id="7" rel="obj1">
                <node begin="3" buiging="met-e" end="4" id="8" lemma="al" naamval="stan" npagr="agr" pdtype="det" pos="det" positie="prenom" postag="VNW(onbep,det,stan,prenom,met-e,agr)" pt="vnw" rel="det" root="alle" vwtype="onbep" word="alle" />
                <node begin="4" buiging="met-e" end="5" getal-n="mv-n" graad="basis" id="9" lemma="werkloos" pos="adj" positie="nom" postag="ADJ(nom,basis,met-e,mv-n)" pt="adj" rel="hd" root="werkloos" word="werklozen" /></node>
        </node>
    </node>
</node>

我现在要做的是将该文件转换为列表,这意味着所有node成为li。我尝试使用以下代码,但控制台返回Uncaught TypeError: Cannot read property 'createDocumentFragment' of undefined

$("#xml-input").html($(this).html().replace(/node/g,"li"));

此外,如果我可以使用当然不会产生有效HTML的列表替换节点。 (仅仅找到替换会导致li&gt; li&gt; li没有任何子列表。)

我认为这可以通过以下一些jQuery来解决:

$("li").each(function() {
    var $this = $(this);
    if ($this.parent().is("li")) {
        $this.before("<ol>");
        $this.siblings(":last").after("</ol>");
    }
});

问题在于,在运行该代码片段之前,浏览器已经自动将错误的HTML转换为正确的HTML。即而不是像这样的东西:

<li>Item 1
    <li>Item 2
        <li>Item 3</li>
    </li>
</li>

浏览器将其修复为:

<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>

因此,对我们生成的HTML运行jQuery似乎是不可能的。

我想做的其他事情是用数据属性替换属性(例如begin,buiging,end,cat et cetera)。这会产生data-begindata-catdata-end等等。我会在整个代码块上运行replace,但我不能:某些节点可能包含实际文本,例如&#34;开始&#34;我不想将文本替换为data-begin,只有属性。我猜测正则表达式的替换应该这样做:将<node视为起点,将>视为结束点。然后替换=之前的所有内容,其中字符串本身前面有data-。不幸的是,我缺乏正则表达式的经验来完成这项工作。

最后,我想将完全彻底检查的HTML添加到另一个div中。像这样:

$("#xml-input").contents().clone().appendTo("#the-list");

理想情况下,最终结果如下:

<li data-begin="0" data-cat="smain" data-end="10" data-id="1" data-rel="--">
    <ol>
        <li data-begin="0" data-cat="np" data-end="5" data-id="2" data-rel="su">
            <ol>
                <li data-begin="0" data-end="1" data-id="3" data-lemma="de" data-lwtype="bep" data-naamval="stan" data-npagr="rest" data-pos="det" data-postag="LID(bep,stan,rest)" data-pt="lid" data-rel="det" data-root="de" data-word="De" />
                <li data-begin="1" data-end="2" data-genus="zijd" data-getal="ev" data-graad="basis" data-id="4" data-lemma="helft" data-naamval="stan" data-ntype="soort" data-pos="noun" data-postag="N(soort,ev,basis,zijd,stan)" data-pt="n" data-rel="hd" data-root="helft" data-word="helft" />
                <li data-begin="2" data-cat="pp" data-end="5" data-id="5" data-rel="mod">
                    <ol>
                        <li data-begin="2" data-end="3" data-id="6" data-lemma="van" data-pos="prep" data-postag="VZ(init)" data-pt="vz" data-rel="hd" data-root="van" data-vztype="init" data-word="van" />
                        <li data-begin="3" data-cat="np" data-end="5" data-id="7" data-rel="obj1">
                            <ol>
                                <li data-begin="3" data-buiging="met-e" data-end="4" data-id="8" data-lemma="al" data-naamval="stan" data-npagr="agr" data-pdtype="det" data-pos="det" data-positie="prenom" data-postag="VNW(onbep,det,stan,prenom,met-e,agr)" data-pt="vnw" data-rel="det" data-root="alle" data-vwtype="onbep" data-word="alle" />
                                <li data-begin="4" data-buiging="met-e" data-end="5" data-getal-n="mv-n" data-graad="basis" data-id="9" data-lemma="werkloos" data-pos="adj" data-positie="nom" data-postag="ADJ(nom,basis,met-e,mv-n)" data-pt="adj" data-rel="hd" data-root="werkloos" data-word="werklozen" />
                            </ol>
                        </li>
                    </ol>
                </li>
            </ol>
        </li>
    </ol>
</li>

我希望一切都清楚。如果没有,请评论。这是一个fiddle来玩。

编辑1。

考虑到@ CBroe的评论和an answer on another question我尝试了jQuery的parseXML()函数,但很快就遇到了麻烦。我无法将node替换为li,并且附加不会按正确的顺序发生。这是another fiddle

var xml = $("#xml-input").html(),
    xmlParsed = $.parseXML(xml),
    xmlObject = $(xmlParsed);

function output(nodes) {
    nodes.each(function () {
        output($(this).children('node'));
        $(this).replaceWith(function () {
            return $("<li />", {
                html: this.html()
            });
        }).appendTo("#the-list");
    });
}
output(xmlObject.children('node'));

1 个答案:

答案 0 :(得分:1)

好的,所以这是我修改过的函数版本http://jsfiddle.net/87sr0dn7/9/

function output(nodes) {
    var newList = $("<ol>");
    nodes.each(function (x, e) {
        var newLI = $("<li>");
        for (var i = 0, l = e.attributes.length, a=null; i < l; i++) {
            a = e.attributes[i];
            newLI.attr("data-"+a.nodeName, a.nodeValue);
            newLI.append("data-"+a.nodeName + '=' + a.nodeValue + ' ');
        }
        newLI.append(output($(this).children('node')));
        newList.append(newLI);
    });
    return newList;
}

正如我所说的,我已经在这里进行了“真正的递归” - 你有一个嵌套在未知数量级别上的node个元素的结构,所以递归是要走的路。

首先,创建一个新的ol元素,然后循环当前级别的所有node元素。
在每次循环迭代中,创建节点的新li元素,然后在节点的所有属性上有另一个循环 - 正如我所说,我在“vanilla JS”中完成了这个,因为我可以找不到在jQuery中循环遍历节点的所有属性的简单方法,并且在JavaScript的DOM实现中,这已经有点“内置”了。因此,对于每个属性,都会获取其名称和值,并将li添加为具有给定值的新data_…属性。

然后跟随对当前节点的子节点的递归调用,该节点为其下面的节点返回ol / li集,并且该调用的结果被附加到{{ 1}},之前它本身被附加到我们在开头创建的li。最后,返回新的ol列表......


如果您只想将一个特定属性的值作为ol的文本内容,那么只需检查当前处理的属性的li是否是您要查找的属性 - 如果是这样,它会附加到nodeName的HTML内容中,否则不会:

li

http://jsfiddle.net/87sr0dn7/10/

结果看起来有点奇怪,因为空的if (a.nodeName == "word") { newLI.append("data-" + a.nodeName + '=' + a.nodeValue + ' '); } 元素(对于没有li属性的节点)现在根本没有直接文本内容(仅{{1}多个word显示在一行...但是根据您的需要格式化这是另一回事。 (此外,这可以通过f.e.简单地在每个li中放置一个不间断的空格来开始,http://jsfiddle.net/87sr0dn7/11/