【问题标题】:Python lxml XPath SyntaxError: invalid predicatePython lxml XPath SyntaxError:无效谓词
【发布时间】:2017-10-18 00:52:16
【问题描述】:

这是描述表单的 XML 文件的一部分:

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfHouse>
<XmlForm>
<houseNum>1</houseNum>
 <plan1> 
  <coord>
    <X> 1.2  </X>
    <Y> 2.1  </Y>
    <Z> 3.0  </Z>
  </coord>
  <color> 
    <R> 255 </R>
    <G> 0   </G>
    <B> 0   </B>
  </color>
 </plan1>
 <plan2>
  <coord>  
    <X> 21.2  </X>
    <Y> 22.1  </Y>
    <Z> 31.0  </Z>
  </coord>
  <color> 
    <R> 255 </R>
    <G> 0   </G>
    <B> 0   </B>
</color>
 </plan2> 
</XmlForm>


<XmlForm>
<houseNum>2</houseNum>
 <plan1> 
  <coord>
    <X> 11.2  </X>
    <Y> 12.1  </Y>
    <Z> 13.0  </Z>
  </coord>
  <color> 
    <R> 255 </R>
    <G> 255   </G>
    <B> 0   </B>
  </color>
 </plan1>
 <plan2>
  <coord>  
    <X> 211.2  </X>
    <Y> 212.1  </Y>
    <Z> 311.0  </Z>
  </coord>
  <color> 
    <R> 255 </R>
    <G> 0   </G>
    <B> 255   </B>
</color>
 </plan2> 
</XmlForm>
</ArrayOfHouse>

这是我为房子1和2恢复每个计划的坐标的代码,问题出在coord=tree.findall("XmlForm/[houseNum=str(houseindex)]这一行,使用houseindex.__str__()时出现同样的问题

import pandas as pd
import numpy as np
from lxml import etree
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
tree =etree.parse("myexample.xml")
#recuperate the columns name for pandas dataframe
planlist=tree.findall("XmlForm/[houseNum='1']/")

columns=[]

for el in planlist[1:]:
    columns.append(el.tag)

#Declare pandas dataFrame
df=pd.DataFrame(columns=list('XYZ'),dtype=float)
for houseindex in range(0,2):
    for index in range(len(columns)):

        coord=tree.findall("XmlForm/[houseNum=str(houseindex)]/"+columns[index]+"/coord/")
        XYZ=[]
        for cc in coord:
            XYZ.append(cc.text)
        df.loc[index]=XYZ
print(df)

【问题讨论】:

    标签: python xml parsing xpath lxml


    【解决方案1】:

    您显然希望在构造 XPath 表达式之前用 Python 解释 str(houseindex)。 (您的错误消息告诉您 str() 不是 XPath 函数。)

    因此,将coord=tree.findall()的参数从

    "XmlForm/[houseNum=str(houseindex)]/"+columns[index]+"/coord/"
    

    "XmlForm/[houseNum="+str(houseindex)+"]/"+columns[index]+"/coord/"
    

    对该 XPath 的另外两个修复:

    1. 删除XmlForm 的谓词前的/
    2. houseNum 的相等性测试周围添加引号。

    没有更多语法错误的最终 XPath

    以下 XPath 结合了所有三个修复,并且没有进一步的语法错误:

    "XmlForm[houseNum='"+str(houseindex)+"']/"+columns[index]+"/coord/"
    

    【讨论】:

    • 我在同一行中收到相同的错误消息。第 64 行,在 coord=tree.findall("XmlForm/[houseNum="+str(houseindex)+"]/"‌​‌​+columns[index]+"/‌​co‌​ord/") ...raise SyntaxError("invalid predicate") SyntaxError: invalid predicate –
    • 抱歉,还有两个额外的 XPath 语法错误需要修复。答案已更新。
    【解决方案2】:

    您不会将“houseindex”注入您的字符串。在您的 houseindex 循环中也要小心,因为您当前使用对应于 0 和 1 的 range(0, 2)。根据您的 xml 示例,您宁愿使用 range(1, 3)。

    我相信你想要这样的东西(我稍微重构了你的代码以提高可读性):

    import pandas as pd
    from lxml import etree
    
    tree = etree.parse("myexample.xml")
    
    # recuperate the columns name for pandas dataframe
    plan_list = tree.findall("XmlForm/[houseNum='1']/")
    columns = [el.tag for el in plan_list[1:]]
    
    # Declare pandas dataFrame
    data = list()
    for house_index in range(1, 3):
        for column in columns:
    
            element_text = "XmlForm/[houseNum='{index}']/{column}/coord/".format(index=house_index, column=column)
            coord = tree.findall(element_text)
            row = [cc.text for cc in coord]
            data.append(row)
    
    df = pd.DataFrame(data, columns=list('XYZ'), dtype=float)
    print(df)
    

    【讨论】:

    • 不过,理想情况下,应避免通过字符串连接来构造 XPath 表达式。 (a) 存在代码注入攻击的风险,并且 (b) 每次执行 XPath 表达式时都要对其进行编译。如果 Python API 允许,最好编译一个包含变量引用的 XPath 表达式,然后在执行表达式时将值绑定到变量。
    猜你喜欢
    • 2016-02-23
    • 1970-01-01
    • 1970-01-01
    • 2017-10-12
    • 1970-01-01
    • 1970-01-01
    • 2016-07-26
    • 1970-01-01
    • 2021-02-03
    相关资源
    最近更新 更多