【问题标题】:Using lxml.etree with no root/parent element使用没有根/父元素的 lxml.etree
【发布时间】:2013-05-16 20:48:05
【问题描述】:

我有一些看起来像这样的 SGML

<!DOCTYPE sometype>
<ITEM>
<DATE>19-OCT-1987</DATE>
<TEXT>
<TITLE>I AM THE TITLE</TITLE>
<AUTHOR>I AM THE AUTHOR</AUTHOR>
<DATELINE>WHEN I WAS CREATED</DATELINE><BODY>
I WANT TO PRESERVE THIS TAG!
</BODY></TEXT>
</ITEM>
<ITEM>...

我尝试使用 lxml.html 对其进行解析,但它似乎剥离了我需要保留的 BODY 标签。接下来我尝试使用 lxml.etree,但正如您所见,所有 ITEM 标记都没有共同的父元素。我目前使用的代码

doc = """<!DOCTYPE sometype>
<ITEM>
<DATE>19-OCT-1987</DATE>
<TEXT>
<TITLE>I AM THE TITLE</TITLE>
<AUTHOR>I AM THE AUTHOR</AUTHOR>
<DATELINE>WHEN I WAS CREATED</DATELINE><BODY>
I WANT TO PRESERVE THIS TAG!
</BODY></TEXT>
</ITEM>"""

from lxml import etree
parser = etree.XMLParser(recover=True) # I have invalid HTML chars to ignore
sgml = etree.fromstring(doc, parser)

现在 sgml 只是第一个 ITEM 元素。我需要它是所有 ITEM 元素。有任何想法吗? lxml.html 做我想做的事,但默认情况下它会去除 BODY 标记,而且我还没有找到禁用此行为的方法。

【问题讨论】:

  • 没有父元素会使文档无效的 XML;将其视为 HTML 也是不正确的,因为它实际上也不是 HTML。您必须改用 SGML 解析器。 lxml 能胜任这项任务,因为底层的libxml2 不能胜任这项任务。
  • sgmllib library 是 Python 标准库的一部分。不幸的是,解析器被认为是过时的,在 Python 3 中不再可用,但它可能在这里满足您的需求。
  • 另一种选择是将文档转换为 XML;为此,您还需要拥有 DTD。见Parse SGML with Open Arbitrary Tags in Python 3
  • 谢谢,这是我担心的。我希望避免使用已弃用的库,但我想我必须这样做。

标签: python lxml


【解决方案1】:

没有共同的父元素?只做一个! 您可以将它们重写为具有父元素,例如 ROOT。在文档末尾的第一个 &lt;ITEM&gt;&lt;/ROOT&gt; 之前插入 &lt;ROOT&gt;。以编程方式进行操作非常简单,即使您必须保留实际的磁盘内容。

例如。

<!DOCTYPE sometype>
<ROOT>
<ITEM>
<DATE>19-OCT-1987</DATE>
<TEXT>
<TITLE>I AM THE TITLE</TITLE>
<AUTHOR>I AM THE AUTHOR</AUTHOR>
<DATELINE>WHEN I WAS CREATED</DATELINE><BODY>
I WANT TO PRESERVE THIS TAG!
</BODY></TEXT>
</ITEM>
<ITEM>
<DATE>19-OCT-1879</DATE>
<TEXT>
<TITLE>I AM THE TITLE</TITLE>
<AUTHOR>I AM THE AUTHOR</AUTHOR>
<DATELINE>WHEN I WAS CREATED</DATELINE><BODY>
I WANT TO PRESERVE THIS TAG!
</BODY></TEXT>
</ITEM>
<ITEM>
<DATE>19-OCT-9871</DATE>
<TEXT>
<TITLE>I AM THE TITLE</TITLE>
<AUTHOR>I AM THE AUTHOR</AUTHOR>
<DATELINE>WHEN I WAS CREATED</DATELINE><BODY>
I WANT TO PRESERVE THIS TAG!
</BODY></TEXT>
</ITEM>
</ROOT>

我刚刚尝试过,它似乎可以满足您的要求。保存为 /tmp/goodfoo 并加载lxml.etree.fromstring(allcontent);然后我访问了你说“想要保留”的文本:b.getchildren()[0].getchildren()[-1].getchildren()[-1].text

(即获取第一个ITEM,获取其TEXT元素,获取TEXT元素的BODY元素,返回BODY元素的任意文本内容。)

【讨论】:

    猜你喜欢
    • 2012-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-20
    • 1970-01-01
    • 1970-01-01
    • 2013-03-18
    相关资源
    最近更新 更多