3 回答

TA贡献1789条经验 获得超10个赞
我宁愿在 Python 中使用 XSLT 3.0(甚至 2.0!),但还没有时间弄清楚如何使用 Saxon/C。
另一种选择是使用iterparse().
例子...
XML 输入(固定为格式良好并添加第二个level3用于测试)
<root>
<level1>
<level2>
<topid>1</topid>
<level3>
<subtopid>1</subtopid>
<level4>
<subid>1</subid>
<descr>test</descr>
</level4>
<level4>
<subid>2</subid>
<descr>test2</descr>
</level4>
</level3>
<level3>
<subtopid>2</subtopid>
<level4>
<subid>1</subid>
<descr>test</descr>
</level4>
<level4>
<subid>2</subid>
<descr>test2</descr>
</level4>
</level3>
</level2>
</level1>
</root>
Python
from lxml import etree
import csv
context = etree.iterparse("test.xml", events=("start", "end"))
fields = ("topid", "subtopid", "subid", "descr")
with open("test.csv", "w", newline="", encoding="utf8") as xml_data_to_csv:
csv_writer = csv.DictWriter(xml_data_to_csv, fieldnames=fields,
delimiter=",", quoting=csv.QUOTE_MINIMAL)
csv_writer.writeheader()
topid = None
subtopid = None
values = {}
for event, elem in context:
tag = elem.tag
text = elem.text
if tag == "topid" and text:
topid = text
if tag == "subtopid" and text:
subtopid = text
if tag == "subid" and text:
values["subid"] = text
if tag == "descr" and text:
values["descr"] = text
if event == "start" and tag == "level4":
# Build a dict containing all of the "fields" with default values of "Unknown".
values = {key: "Unknown" for key in fields}
if event == "end" and tag == "level4":
values["topid"] = topid
values["subtopid"] = subtopid
csv_writer.writerow(values)
elem.clear()
CSV 输出
topid,subtopid,subid,descr
1,1,1,test
1,1,2,test2
1,2,1,test
1,2,2,test2

TA贡献1805条经验 获得超10个赞
一种可能性是使用 XSLT 3.0 流。这里有两个挑战:
(a) 使您的代码可流式传输。如果没有看到样式表代码,我们无法判断这有多难。
(b) 安装和运行流式 XSLT 3.0 处理器。这取决于您对 Python 环境的锁定程度。如果必须在 Python 中完成,您可以尝试安装 Saxon/C。另一种方法是调用不同的环境,在这种情况下您有更多选择,例如您可以在 Java 上运行 Saxon-EE。
之后
看你贴的代码,比较奇怪
<xsl:for-each select="level1/level2/level3/level4">
<xsl:value-of select="ancestor::root/level1/level2/topid" />
我怀疑您想输出topid“当前”level2元素的 ,但这不是这样做的(在 XSLT 1.0 中它将打印第一个的值level2/topic,在 XSLT 2.0+ 中将打印所有level2/topic元素的值。我怀疑你真的想要这样的东西:
<xsl:for-each select="level1/level2/level3/level4">
<xsl:value-of select="ancestor::level2/topid" />
<xsl:value-of select="$delimiter" />
<xsl:value-of select="ancestor::level3/subtopid" />
<xsl:value-of select="$delimiter" />
<xsl:value-of select="subid" />
<xsl:value-of select="$delimiter" />
<xsl:value-of select="descr" />
<xsl:value-of select="$newline" />
</xsl:for-each>
这几乎是可流式传输的,但不完全是。流式传输不允许您回到 toppid 和 subtopid 元素。使其可流式传输的最简单方法可能是将这些元素的最新值保存在累加器中:
<xsl:accumulator name="topid" as="xs:string" initial-value="''">
<xsl:accumulator-rule match="topid/text()" select="string(.)"/>
</xsl:accumulator>
<xsl:accumulator name="subtopid" as="xs:string" initial-value="''">
<xsl:accumulator-rule match="subtopid/text()" select="string(.)"/>
</xsl:accumulator>
然后访问这些值:
<xsl:for-each select="level1/level2/level3/level4">
<xsl:value-of select="accumulator-before('topid')" />
<xsl:value-of select="$delimiter" />
<xsl:value-of select="accumulator-before('subtopid')" />
<xsl:value-of select="$delimiter" />
<xsl:value-of select="subid" />
<xsl:value-of select="$delimiter" />
<xsl:value-of select="descr" />
<xsl:value-of select="$newline" />
</xsl:for-each>

TA贡献1799条经验 获得超8个赞
Saxon/C 和 python 可以工作:
一位用户已成功使用 Boost.Python 与 C++ 库交互。
另一个用户以不同的方式完成了接口:https : //github.com/ajelenak/pysaxon
添加回答
举报