【问题标题】:Using elementree, lxml - the only (.//) wildcard works for findall - cannot use relative paths?使用 elementree,lxml - 唯一适用于 findall 的 (.//) 通配符 - 不能使用相对路径?
【发布时间】:2021-01-16 21:53:06
【问题描述】:

我有一个高度嵌套的长 xml 文件,我需要对其进行解析并进入 pandas DataFrame。

这是我的 XML:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE PPP
  SYSTEM 'PPP.DTD'>
<book chg="R" model="AB" >
    <chapter chapnbr="09" chg="U" key="EN49" >
        <effect effrg="Afcd"/>
        <title>HOW TO WIN</title>
        <section chapnbr="09" chg="U" key="Edff" revdate="20100701" sectnbr="102">
            <title>What a start</title>
            <subject chapnbr="09" chg="U" key="Edff" revdate="20100701" sectnbr="102" subjnbr="00">
                <title>1.A</title>
                <pgblk chapnbr="09" chg="U" confnbr="00" key="Edff00" pgblknbr="00" revdate="20200701" sectnbr="102" subjnbr="00">
                    <effect effrg="12"/>
                    <title>1.A.i) Plan Ahead for the worst</title>
                    <prclist1>
                        <prcitem1 adns-numbering="8" adns-title="learning my way with help of good people" >
                            <effect effrg="Edff"/>
                            <prcitem asFragment="true">
                                <title>1.A.i) Plan Ahead for the worst</title>
                                <para>It was a cold January night, and I had too much whisky. 
                                    <refblock>
                                        09-102-00
                                        <refint rrr="22,445,555,555,555" refid="Edff0898">
                                            <effect effrg="Edff0899"/>
                                            0910200</refint>
                                    </refblock>. </para>
                                <para>In more usual circumstances, I possesed the self-control. Not this time 
                                    <refblock>
                                        09-102-00-1111
                                        <refint rrr="sdf,2323,2323" refid="Edff123">
                                            <effect effrg="Edff12434"/>
                                            09-102-00</refint>
                                    </refblock>. </para>
                            </prcitem>
                        </prcitem1>
                    </prclist1>
                </pgblk>
            </subject>
        </section>
    </chapter>
</book>

由于我不知道的原因,我无法使用相对 XPath 进行提取。只有findall('.//') 有效,但当然会输出完整的文件。

在高层次上,我可以得到 xml 解析

from lxml import etree

tree = etree.parse('file.xml')
root = tree.getroot()

我还可以获取每个元素的绝对路径:


for e in root.iter():
    print(tree.getpath(e))

这给出了(下面是一个示例,我的实际 xml 更嵌套,输出 x3 倍于下面的路径):

/book
/book/chapter
/book/chapter/effect
/book/chapter/title
/book/chapter/section
/book/chapter/section/title
/book/chapter/section/subject

然后我需要从 xml 的特定区域提取标签和文本

但是,如果尝试使用绝对路径或相对路径,则字典输出 d 仍为空。

d={}

for item in root.findall('./section/title'): 
    d[item.tag] = item.text

同样

findall('.//section/title')

再一次,空字典

findall('/book/chapter/section/title')

唯一有效的 xpath 是:

findall('.//')

【问题讨论】:

  • 您可能希望将您的 xml 文件(的一部分)显示为示例。你在使用 xml 命名空间吗?
  • (1) 您必须包含您的 XML 以获得最佳帮助。 (2) 您对术语absoluterelative 的使用已关闭:.//./ 都是相对的; /// 都是绝对的。
  • @AdrianW 不使用命名空间
  • @kjhughes 感谢您指出这一点。我现在也包含了我的 xml 示例。
  • ./book/chapter/section/title.//title 都应该与 findall() 一起使用以选择 title 元素。看来.//section/title 也应该至少找到一个title,尽管您的报告。重新检查?

标签: python xml xpath lxml elementtree


【解决方案1】:

findall() 不接受绝对路径名。您需要相对路径名。

'.//section/title' 确实有效,但它返回title 标签。因此,无论有多少匹配项,您最终都会在您的 dict 中得到一个名为 title 的键,为什么可能不是您想要的。

如果你想使用标题作为章节的索引,你可以这样做:

d = dict((item.text, item.getparent()) for item in root.findall('.//section/title'))

从您的示例 XML 中,这将创建一个带有键 What a start 和章节元素作为值的字典。

如果您想使用 XPath 表达式的全部功能,我建议您使用XPathEvaluator

from lxml import etree

tree = etree.parse('file.xml')

xev = etree.XPathEvaluator(tree)

d = dict((item.text, item.getparent()) for item in xev('/book/chapter/section/title'))

for k, v in d.items():
    print(f"{k} -> {v.tag}")

输出:

What a start -> section

【讨论】:

  • 非常感谢。这很有帮助。我仍然不清楚如何在不通过指定 ('/a/b/c/d/e') 逐步降级的情况下达到“曾曾孙”元素?
  • 我没有设法使用 XPathEvaluator 和 '//' 进入特定节点,并设法使用不同的源 xml 文件进行复制。我现在遇到的麻烦是遍历 xml 文件的文件夹。由于某种原因,没有找到文件
  • 这似乎是两个截然不同的问题。首先,请查看XPath 1.0 以了解有关 XPath 功能的更多信息。您可以从任何元素创建一个新的 XPathEvaluator 作为新起点并从那里导航。有像descendant-or-self:: 这样的轴说明符。所以,真的有很多可能性。不清楚这里真正的问题是什么。简单地迭代孩子也可能是一种解决方案,具体取决于您想要做什么。可能会为此提出一个新问题。其次,os.walk() 应该是可行的。
  • 谢谢。我问了一个新问题stackoverflow.com/q/65799851/13607357
猜你喜欢
  • 2018-09-11
  • 1970-01-01
  • 2010-10-28
  • 2011-07-12
  • 2012-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-14
相关资源
最近更新 更多