【问题标题】:lxml xpath not working if default namespace is present如果存在默认命名空间,lxml xpath 不起作用
【发布时间】:2020-01-03 15:40:17
【问题描述】:

我的组织正在从 python 2.7 迁移到 python 3.7。有一些python代码我没有写,但必须迁移。代码使用 xml.xpath 来解析 xml。

鉴于 xml.xpath 在 python 3.7 中不可用。我正在尝试移植代码以使用 lxml.etree 中的 Xpath。目的是尽量减少代码更改量。

我已经粘贴了当前的实现以及我将其移植到的代码。由于 XML 具有默认命名空间,移植的代码不起作用。

当前代码

>>> from xml import xpath
>>> from   xml.dom.minidom import parseString
>>> Test_XML = '<ibml:validateTradeStatusRequest xmlns="http://www.fpml.org/2005/FpML-4-2" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:ibml="http://ibml.jpmorgan.com/2005" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ibmlVersion="1-56" version="4-2" xsi:schemaLocation="http://ibml.jpmorgan.com/2005C:\\IBTIBML\\trunk\\src\\xsd\\IBML.xsd"><header><sentBy>test_value</sentBy><sendTo>test_value</sendTo><creationTimestamp>2012-06-06T08:23:20.613</creationTimestamp></header><tradeReference></tradeReference></ibml:validateTradeStatusRequest>'

>>> doc = parseString( Test_XML )
>>> ctx = xpath.Context.Context( doc, processorNss = {'ibml' : 'http://ibml.jpmorgan.com/2005'} )
>>> expr = xpath.Compile( '/ibml:validateTradeStatusRequest/header/sentBy' )
>>> node = expr.evaluate(ctx)
>>> node[0].childNodes[0].data
u'test_value'
>>> 

尝试将其移植到 lxml.etree。但它不起作用,因为 XML 具有默认命名空间。

>>> from lxml import etree as ET
>>> element = ET.fromstring( Test_XML )
>>> element.xpath( '/ibml:validateTradeStatusRequest/header/sentBy', namespaces = {'ibml' : 'http://ibml.jpmorgan.com/2005'} )
[]

但是,如果我删除默认命名空间,那么 xpath 评估就可以正常工作。 但这不是理想的解决方案,因为 XML 创建超出了代码的范围。此外,也无法更改 xpath 查询,因为这也在代码范围之外。

>>> Test_XML_No_Default_NS = '<ibml:validateTradeStatusRequest xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:ibml="http://ibml.jpmorgan.com/2005" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ibmlVersion="1-56" version="4-2" xsi:schemaLocation="http://ibml.jpmorgan.com/2005C:\\IBTIBML\\trunk\\src\\xsd\\IBML.xsd"><header><sentBy>test_value</sentBy><sendTo>test_value</sendTo><creationTimestamp>2012-06-06T08:23:20.613</creationTimestamp></header><tradeReference></tradeReference></ibml:validateTradeStatusRequest>'

>>> ee = ET.fromstring( Test_XML_No_Default_NS )
>>> ee.xpath( '/ibml:validateTradeStatusRequest/header/sentBy', namespaces = {'ibml' : 'http://ibml.jpmorgan.com/2005'} )
[<Element sentBy at 0x1546b058>]
>>> node = _
>>> node[0].text
'test_value'

对我如何前进有什么建议吗?

【问题讨论】:

  • 代码使用 xml.xpath 解析 xml。什么是 xml.xpath? “当前代码”中没有导入语句。
  • 我发现 xml.xpath 是旧的且未维护的 PyXML 包 (sourceforge.net/projects/pyxml) 的一部分。
  • @mzjn 抱歉给您添麻烦了。编辑了问题并添加了导入语句。
  • 无论如何,我看不到在不更改 XPath 查询字符串的情况下做你想做的事的方法。 lxml 还需要默认命名空间的前缀:NSMAP = {'ibml':'http://ibml.jpmorgan.com/2005', 'd': 'http://www.fpml.org/2005/FpML-4-2'})。然后element.xpath('/ibml:validateTradeStatusRequest/d:header/d:sentBy', namespaces=NSMAP) 就可以了。

标签: python xml lxml python-3.7


【解决方案1】:

我不确定这是否会直接回答您的问题,但请尝试一下,看看它是否有效(可能需要修改)

import lxml.etree
Test_XML = '<?xml version="1.0" encoding="UTF-8"?><ibml:validateTradeStatusRequest xmlns="http://www.fpml.org/2005/FpML-4-2" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:ibml="http://ibml.jpmorgan.com/2005" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ibmlVersion="1-56" version="4-2" xsi:schemaLocation="http://ibml.jpmorgan.com/2005C:\\IBTIBML\\trunk\\src\\xsd\\IBML.xsd"><header><sentBy>test_value1</sentBy><sendTo>test_value2</sendTo><creationTimestamp>2012-06-06T08:23:20.613</creationTimestamp></header><tradeReference></tradeReference></ibml:validateTradeStatusRequest>'
xml = bytes(bytearray(Test_XML, encoding='utf-8')) 
ee = etree.XML(xml)
target = ee.xpath( '//ibml:validateTradeStatusRequest', namespaces = {'ibml' : 'http://ibml.jpmorgan.com/2005'} )
print(target[0].xpath('//text()')[0])

输出:

test_value1

【讨论】:

  • 感谢您的建议。我想避免对查询字符串进行任何更改。这段代码被许多模块使用,查询字符串由这些模块形成,超出了这段代码的范围。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-25
  • 2013-06-23
  • 2010-10-07
  • 2011-12-24
  • 1970-01-01
  • 2011-08-31
相关资源
最近更新 更多