使用 Python lxml 解析带有条件的 ONIX xml
Posted
技术标签:
【中文标题】使用 Python lxml 解析带有条件的 ONIX xml【英文标题】:Parsing an ONIX xml with conditions using Python lxml 【发布时间】:2022-01-20 17:06:40 【问题描述】:我正在尝试使用 Python lxml
解析器从 ONIX XML format 文件中提取一些信息。
除此之外,我对文档感兴趣的部分如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<ProductSupply>
<SupplyDetail>
<Supplier>
<SupplierRole>03</SupplierRole>
<SupplierName>EGEN</SupplierName>
</Supplier>
<ProductAvailability>40</ProductAvailability>
<Price>
<PriceType>01</PriceType>
<PriceAmount>0.00</PriceAmount>
<Tax>
<TaxType>01</TaxType>
<TaxRateCode>Z</TaxRateCode>
<TaxRatePercent>0</TaxRatePercent>
<TaxableAmount>0.00</TaxableAmount>
<TaxAmount>0.00</TaxAmount>
</Tax>
<CurrencyCode>NOK</CurrencyCode>
</Price>
<Price>
<PriceType>02</PriceType>
<PriceQualifier>05</PriceQualifier>
<PriceAmount>0.00</PriceAmount>
<Tax>
<TaxType>01</TaxType>
<TaxRateCode>Z</TaxRateCode>
<TaxRatePercent>0</TaxRatePercent>
<TaxableAmount>0.00</TaxableAmount>
<TaxAmount>0.00</TaxAmount>
</Tax>
<CurrencyCode>NOK</CurrencyCode>
</Price>
</SupplyDetail>
</ProductSupply>
我需要在以下条件下领取价格金额:
PriceType='02' and CurrencyCode='NOK' and PriceQualifier='05'
我试过了:
price = p.find(
"ProductSupply/SupplyDetail[Supplier/SupplierRole='03']/Price[PriceType='02' \
and CurrencyCode='NOK' and PriceQualifier='05']/PriceAmount").text
由于某种原因,我的带有 and
运算符的 XPath 无法正常工作并出现以下错误:
File "<string>", line unknown
SyntaxError: invalid predicate
知道如何处理它吗? 非常感谢任何帮助!
【问题讨论】:
尝试使用.xpath()
而不是.find()
。
【参考方案1】:
TL;DR:使用xpath()
,因为find*()
方法不支持像and
这样的布尔运算符。
作为Daniel suggested,您应该使用lxml 的解析器方法xpath()
来处理(相当复杂的)XPath 表达式。
XPath
您的 XPath 表达式包含 节点测试 和 predicates,它们使用 boolean operator and
(XPath 1.0):
ProductSupply/SupplyDetail[Supplier/SupplierRole='03']/Price[PriceType='02' \
and CurrencyCode='NOK' and PriceQualifier='05']/PriceAmount
提示:在线测试(见Xpather demo)。这断言它按预期找到了单个元素 <PriceAmount>0.00</PriceAmount>
。
使用find()
方法
根据 Python 文档,您可以使用以下接受匹配表达式(例如 XPath)作为参数的 find 方法:
find
findAll
问题:对find()
的 XPath 语法支持有限
虽然他们的supported XPath syntax是有限的!
此限制包括逻辑运算符,例如您的 and
。 Karl Thornton 在他的页面 XML parsing: Python ~ XPath ~ logical AND | Shiori 上对此进行了解释。
另一方面,note on lxml documentation 更喜欢他们:
.find*()
方法通常比成熟的 XPath 支持更快。它们还通过 .iterfind() 方法支持增量树处理,而 XPath 总是在返回它们之前收集所有结果。因此,当不需要高度选择性的 XPath 查询时,出于速度和内存方面的考虑,建议使用它们而不是 XPath。
(强调我的)
使用lxml的xpath()
让我们从更安全、更丰富的xpath()
函数开始(在过早优化之前)。例如:
# the node predicates to apply within XPath
sd_predicate = "[Supplier/SupplierRole='03']"
p_predicate = "[PriceType='02' and CurrencyCode='NOK' and PriceQualifier='05']"
pa_xpath = f"ProductSupply/SupplyDetailsd_predicate/Pricep_predicate/PriceAmount" # building XPath including predicates with f-string
print("Using XPath:", pa_xpath) # remove after debugging
root = tree.getroot()
price_amount = root.xpath(pa_xpath)
print("XPath evaluated to:", price_amount) # remove after debugging
另见:
官方lxml指南:XPath and XSLT with lxml Using XPath in Python with LXML【讨论】:
哇,谢谢你的详细解答!以上是关于使用 Python lxml 解析带有条件的 ONIX xml的主要内容,如果未能解决你的问题,请参考以下文章