【问题标题】:python lxml findall with multiple namespaces具有多个命名空间的 python lxml findall
【发布时间】:2016-04-22 02:56:07
【问题描述】:

我正在尝试使用 lxml 解析具有多个命名空间的 XML 文档,但我一直坚持让 findall() 方法返回一些内容。

我的 XML:

<MeasurementRecords xmlns="http://www.company.com/common/rsp/2012/07"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         
                    xsi:schemaLocation="http://www.company.com/common/rsp/2012/07 RSP_EWS_V1.6.xsd">
    <HistoryRecords>
        <ValueItemId>100_0000100004_3788_Resource-0.customId_WSx Data Precip Type</ValueItemId>
            <List>
                <HistoryRecord>
                    <Value>60</Value>
                    <State>Valid</State>
                    <TimeStamp>2016-04-20T12:40:00Z</TimeStamp>
                </HistoryRecord>
            </List>
        </HistoryRecords>
    <HistoryRecords>
</MeasurementRecords>

我的代码:

from lxml import etree
from pprint import pprint

RSPxmlFile = '/home/user/Desktop/100_0000100004_3788_20160420144011263_records.xml'

with open (RSPxmlFile, 'rt') as f:
    tree = etree.parse(f)

root = tree.getroot()

for node in tree.findall('MeasurementRecords', root.nsmap):
    print node
    print "parameter = ", node.text

给予:

ValueError: empty namespace prefix is not supported in ElementPath

阅读this后尝试的一些实验:

>>> root.nsmap
{'xsi': 'http://www.w3.org/2001/XMLSchema-instance', None: http://www.company.com/common/rsp/2012/07'}

>>> nsmap['foo']=nsmap[None]
>>> nsmap.pop(None)
'http://www.company.com/common/rsp/2012/07'
>>> nsmap
{'xsi': 'http://www.w3.org/2001/XMLSchema-instance', 'foo': 'http://www.company.com/common/rsp/2012/07'}
>>> tree.xpath("//MeasurementRecords", namespaces=nsmap)
[]
>>> tree.xpath('/foo:MeasurementRecords', namespaces=nsmap)
[<Element {http://www.company.com/common/rsp/2012/07}MeasurementRecords at 0x6ffffda5290>]
>>> tree.xpath('/foo:MeasurementRecords/HistoryRecords', namespaces=nsmap)
[]

但这似乎没有帮助。

所以,更多的实验:

>>> tree.findall('//{http://www.company.com/common/rsp/2012/07}MeasurementRecords')
[]
>>> print root
<Element {http://www.company.com/common/rsp/2012/07}MeasurementRecords at 0x6ffffda5290>
>>> print tree
<lxml.etree._ElementTree object at 0x6ffffda5368>
>>> for node in tree.iter():
...     print node
...
<Element {http://www.company.com/common/rsp/2012/07}MeasurementRecords at 0x6ffffda5290>
<Element {http://www.company.com/common/rsp/2012/07}HistoryRecords at 0x6ffffda5cf8>
<Element {http://www.company.com/common/rsp/2012/07}ValueItemId at 0x6ffffda5f38>
...etc...
>>> tree.findall("//HistoryRecords", namespaces=nsmap)
[]
>>> tree.findall("//foo:MeasurementRecords/HistoryRecords", namespaces=nsmap)
[]

我被难住了。我不知道出了什么问题。

【问题讨论】:

    标签: python xpath lxml xml-namespaces


    【解决方案1】:

    如果你从这个开始:

    >>> tree = etree.parse(open('data.xml'))
    >>> root = tree.getroot()
    >>> 
    

    这将无法找到任何元素...

    >>> root.findall('{http://www.company.com/common/rsp/2012/07}MeasurementRecords')
    []
    

    ...但那是因为root MeasurementRecords 元素;它 不包含任何MeasurementRecords 元素。在另一 手,以下工作就好了:

    >>> root.findall('{http://www.company.com/common/rsp/2012/07}HistoryRecords')
    [<Element {http://www.company.com/common/rsp/2012/07}HistoryRecords at 0x7fccd0332ef0>]
    >>> 
    

    使用xpath 方法,您可以执行以下操作:

    >>> nsmap={'a': 'http://www.company.com/common/rsp/2012/07',
    ... 'b': 'http://www.w3.org/2001/XMLSchema-instance'}
    >>> root.xpath('//a:HistoryRecords', namespaces=nsmap)
    [<Element {http://www.company.com/common/rsp/2012/07}HistoryRecords at 0x7fccd0332ef0>]
    

    所以:

    • findallfind 方法需要 {...namespace...}ElementName 语法。
    • xpath 方法需要命名空间前缀 (ns:ElementName),它在提供的 namespaces 映射中查找。 prefix 不必匹配原始文档中使用的前缀,但 namespace url 必须匹配。

    所以这行得通:

    >>> root.find('{http://www.company.com/common/rsp/2012/07}HistoryRecords/{http://www.company.com/common/rsp/2012/07}ValueItemId')
    <Element {http://www.company.com/common/rsp/2012/07}ValueItemId at 0x7fccd0332a70>
    

    或者这行得通:

    >>> root.xpath('/a:MeasurementRecords/a:HistoryRecords/a:ValueItemId',namespaces=nsmap)
    [<Element {http://www.company.com/common/rsp/2012/07}ValueItemId at 0x7fccd0330830>]
    

    【讨论】:

    • 太棒了!非常感谢。是否可以从一个 ValueItemId 元素中返回 Value 节点?我试过这个,但没有用:root.xpath('/a:MeasurementRecords/a:HistoryRecords[a:ValueItemId="100_0000100004_3788_Resource-0.customId_WSx Data Precip Type"]//a:Value',namespaces=nsmap)
    • This question 可能会有所帮助。
    猜你喜欢
    • 2016-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-28
    • 2019-07-26
    • 2011-02-20
    • 2021-12-20
    相关资源
    最近更新 更多