最好的方法是转换自定义XML语法

时间:2011-07-15 18:12:55

标签: python xml parsing tags

使用Python。

所以基本上我有类似XML的标签语法,但标签没有属性。所以<a>但不是<a value='t'>。他们定期与</a>关闭。

这是我的问题。我有一些看起来像这样的东西:

<al>
1. test
2. test2
 test with new line
3.  test3
<al>
    1. test 4
    <al>
        2. test 5
        3. test 6
        4. test 7
    </al>
</al>
4. test 8
</al>

我想把它变成:

<al>
<li>test</li>
<li> test2</li>
<li> test with new line</li>
<li>  test3
<al>
    <li> test 4 </li>
    <al>
        <li> test 5</li>
        <li> test 6</li>
        <li> test 7</li>
    </al>
    </li>
</al>
</li>
<li> test 8</li>
</al>

我并不是在寻找一个完整的解决方案,而是朝着正确的方向努力。我只是想知道这里的人们如何处理这个问题。唯一的REGEX?为无属性标记语法编写完整的自定义解析器?破解现有的XML解析器?等

提前致谢

4 个答案:

答案 0 :(得分:2)

我建议从以下开始:

from xml.dom.minidom import parse, parseString

xml = parse(...)
l = xml.getElementsByTagName('al')

然后遍历l中的所有元素,检查它们的文本子节点(以及递归的<al>节点)。

您可以立即在Python控制台中开始使用它。

可以轻松删除文本节点,然后根据需要拆分文本块chunk.split('\n')并添加<li>个节点。

修改所有<al>个节点后,您可以调用xml.toxml()将结果xml作为文本。

请注意,您从中获取的元素对象将链接回原始xml文档对象,因此请勿删除该过程中的xml对象。

通过这种方式,我个人认为比使用多行regexp更加简单易学。

答案 1 :(得分:2)

您描述语法的方式是“没有属性的XML”。如果是这样,它仍然是XML,那么你可以使用XSLT和XQuery等XML工具。

另一方面,如果允许XML中不允许的内容,我的方法是编写一个处理非XML格式的解析器,并提供与XML兼容的SAX事件。然后,只需插入解析器代替常规XML解析器,就可以使用任何XML技术。

答案 2 :(得分:1)

这取决于你想要用它做什么,如果它是一个脚本,下面就足够了:

cat in.txt | perl -pe 'if(!/<\/?al>/){s#^(\s*)([0-9]+\.)?(.*)$#$1<li>$3</li>#}'

它有效。但我不会说它非常强大;)但如果它是一次性的那就没关系。

答案 3 :(得分:0)

  

我只是想知道这里的人们如何处理这个问题。

我会选择使用解析器。

我的理由是,您尝试执行的操作不仅仅是语法或词汇替换。它更像是语法转换,暗示理解文档的结构

在您的示例中,您不是简单地将每一行括在<li></li>之间;如果这些代表一个“项目”,你还会递归地附上一些跨越多行的文档块。

也许你可以组合一个能够捕获解释逻辑和问题的递归性质的正则表达式,但这样做就像用茶匙挖一个沟槽:你可以< / em>做到这一点,但使用spade(解析器)是一个更合乎逻辑的选择。

使用解析器的另一个原因是“真正的单词”。正则表达式是真正的“语法纳粹”:标记中的一个小故障,它们将无法正常工作。另一方面,所有解析器库都是“灵活的”(统一处理不同的拼写,如<a></a><a/>或HTML的<br>和XHTML的<br/>)和一些 - 如{{{ 3}} - 甚至是“宽容”,这意味着他们会尝试猜测(具有惊人的高准确度)文档作者想要编码的内容,即使文档本身未通过验证。

此外,基于解析器的解决方案比基于正则表达式的解决方案更易于维护。您的文档结构中的一个小变化可能需要彻底改变您的正则表达式[在72小时左右之后,它本质上往往会变得模糊不清他们自己的作者]。

最后,因为您使用的是python和beautifulsoup readability counts ,基于解析器的解决方案可能会产生比非常复杂/长/不明确的正则表达式更多的pythonic代码

HTH!