我想用python lxml xpath解析一个xml文件,结构是这样的。
<body>
<tu changedate="20190822T080742Z" creationdate="20190822T085527Z" creationid="blank" changeid="blank">
<prop type="client"> </prop>
<prop type="project"> </prop>
<prop type="domain"> </prop>
<prop type="subject"> </prop>
<prop type="corrected">no</prop>
<prop type="aligned">no</prop>
<prop type="x-document">Test_EN.docx</prop>
<prop type="x-Project Id">0001</prop>
<prop type="x-Product group">A</prop>
<prop type="x-Product">A</prop>
<prop type="x-Product">B</prop>
<prop type="x-TestList">TestValue1</prop>
<prop type="x-TestList">TestValue2</prop>
<prop type="x-Sample">SampleText</prop>
<prop type="x-Test">TestText</prop>
<prop type="x-Name">TestName</prop>
为了用函数动态地找到节点,我把要找的节点的名字和值保存到变量名中。
node_name = x-Sample
node_value = SampleText
xpath_expression = f'//body/tu/prop[@type="{node_name}"][text()="{node_value}"]'
elements = tree.xpath(xpath_expression)
问题是node_value可以包含双引号,因此产生一个无效的xpath表达式。由于我被lxml卡住了,而且它使用的是xpath 1.0,我无法在字符串中转义。
通过stackoverflow查找,我发现显然只有在xpath 1.0中使用concat才能做到这一点。我还找到了下面发布的函数。
def xpath_string_escape(input_str):
""" creates a concatenation of alternately-quoted strings that is always a valid XPath expression """
parts = input_str.split('"')
return "concat('" + "', \"'\" , '".join(parts) + "', '')"
然后就得到了这个
xpath_expression = '//body/tu/tuv/prop[@type="x-Sample"][text()="concat('SampleText', '')"]'
然而这并没有返回我想要的节点。
另一种方法 你可以用.NET去掉节点值中的双引号。
node_value = translate(//prop[@type="x-Sample"]/text(),'"',"")
然后用contains()代替text()来构建你的XPath表达式。
xpath_expression = f'//body/tu/prop[@type="{node_name}"][contains(.,"{node_value}")]'