如何让PySpark的XPath查询返回含None的等长列表而非省略缺失值
问题
PySpark DataFrame某列存储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查询:
- 提取
data:root/level1/level2/level3/level4/data - 提取
data2:root/level1/level2/level3/data2
返回结果(列表长度不一致):
(1, ["Apple","Banana","Cranberry"], ["Lion","Tiger"]) (2, ["Apple","Banana"], ["Lion","Tiger","Zebra"])
期望结果
(1, ["Apple","Banana","Cranberry"], ["Lion", None, "Tiger"]) (2, ["Apple","Banana", None], ["Lion","Tiger","Zebra"])
解决方案
调整XPath逻辑
核心是基于父容器节点(level3)批量查询,确保每个父节点对应一个结果(存在则返回文本,不存在则返回空字符串),再将空字符串转为None。
调整后的XPath:
- 提取
data:root/level1/level2/level3/string(level4/data) - 提取
data2:root/level1/level2/level3/string(data2)
string()函数会针对每个level3节点,返回其下目标子节点的文本;若子节点不存在,返回空字符串,这样结果列表长度与level3节点数量完全一致。
完整PySpark代码
from pyspark.sql import functions as F # 提取data列表并转换空字符串为None df = df.withColumn( "data_list", F.transform( F.expr("xpath(xml_string, 'root/level1/level2/level3/string(level4/data)')"), lambda x: F.when(x != "", x).otherwise(None) ) ) # 提取data2列表并转换空字符串为None df = df.withColumn( "data2_list", F.transform( F.expr("xpath(xml_string, 'root/level1/level2/level3/string(data2)')"), lambda x: F.when(x != "", x).otherwise(None) ) ) # 查看最终结果 df.select("id", "data_list", "data2_list").show(truncate=False)
结果验证
执行后将得到符合期望的输出:
+---+--------------------------+--------------------------+ |id |data_list |data2_list | +---+--------------------------+--------------------------+ |1 |[Apple, Banana, Cranberry]|[Lion, null, Tiger] | |2 |[Apple, Banana, null] |[Lion, Tiger, Zebra] | +---+--------------------------+--------------------------+
内容的提问来源于stack exchange,提问作者Krushna
相关产品推荐
相关产品推荐

