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
添加回答
舉報