我有一个 PySpark DataFrame,其中有一列包含 XML 字符串,并且我使用带有绝对路径的 XPath 查询从这些 XML 字符串中提取数据。但是,我注意到 XPath 查询返回的列表会忽略不存在的值,而不是在其位置包含 None 。我想保持列表的长度一致,缺少数据的地方填写“无”。
这是我正在使用的示例数据和代码:
data = [
(1, """<root>
<level1>
<level2>
<level3>
<data2>Lion</data2>
<level4>
<data>Apple</data>
</level4>
</level3>
</level2>
<level2>
<level3>
<level4>
<data>Banana</data>
</level4>
</level3>
</level2>
<level2>
<level3>
<data2>Tiger</data2>
<level4>
<data>Cranberry</data>
</level4>
</level3>
</level2>
</level1>
</root>"""),
(2, """<root>
<level1>
<level2>
<level3>
<data2>Lion</data2>
<level4>
<data>Apple</data>
</level4>
</level3>
</level2>
<level2>
<level3>
<data2>Tiger</data2>
<level4>
<data>Banana</data>
</level4>
</level3>
</level2>
<level2>
<level3>
<data2>Zebra</data2>
<level4></level4>
</level3>
</level2>
</level1>
</root>""")
df = spark.createDataFrame(data, ["id", "xml_string"])
XPath 查询返回什么:
对于数据列: (1, [“苹果”,“香蕉”,“蔓越莓”], [“狮子”,“老虎”]) (2, [“苹果”,“香蕉”], [“狮子”,“老虎”,“斑马”]) 我想要什么:
对于数据列: (1,[“苹果”,“香蕉”,“蔓越莓”],[“狮子”,无,“老虎”]) (2、[“苹果”、“香蕉”、无]、[“狮子”、“老虎”、“斑马”])
如何调整我的 XPath 查询?
root/level1/level2/level3/level4/data
root/level1/level2/level3/data2
这很棘手,因为(除非我弄错了)这里的 XPath 实现只是版本 1.0。在更高的 XPath 版本中,您可以编写如下内容:
for $item in root/level1/level2/level3/level4/datreturn
if ($item/data) then
$item/data
else
"NULL"
...并返回一系列项目,这些项目要么是从 XML 中提取的节点(特别是
data
元素节点),要么是为填充缺失的 data
元素而生成的字符串。
不幸的是,XPath 1.0 没有后续版本提供的“序列”数据类型。相反,它具有“nodeset”数据类型,顾名思义,它必然由从 XML 中提取的节点组成。这意味着您的 XPath 查询无法返回节点和字符串的混合。
但是,有一种可能性可以满足您的要求:您可以尝试返回
level4
的第一个子文本节点(这只是空格;换行符和一些空格或制表符),而不是返回“NULL”值
元素没有 data
子元素。
root/level1/level2/level3/level4/data
|
root/level1/level2/level3/level4[not(data)]/text()[1]
|
(集合并集)运算符将连接两个路径表达式的结果,并应确保每个 level4
在结果中得到一个节点。您最终应该得到一个数据框,其中空格字符串代表缺失值,但希望这不会太繁重而难以处理。