gpt4 book ai didi

python - 在 Python 中逐项列出大型 xml 文件

转载 作者:行者123 更新时间:2023-11-30 22:01:18 28 4
gpt4 key购买 nike

我正在设计某种 ETL 管道,我希望首先将输入 XML 数据集拆分为与每个项目相关的单独 XML 文件。输入数据集基本上是特定模型下元数据的导出(当前示例是 EDM)。我对 XSLT 相当满意,并希望使用它来避免在这个问题上使用太多的 Python,而这应该没有那么复杂。

我浏览了许多线程,包括 Lisa Daly 的 Fast_iter(参见 https://www.ibm.com/developerworks/xml/library/x-hiperfparse/ )。我尝试了不同的方法,但在写入文件时我总是陷入困境(没有输出或序列化问题)。正在寻找一些经验丰富的反馈吗?!

数据集结构

<rdf:RDF ...many namespaces...>
<!--ITEM1 NODE-->
<ore:aggregates>
<edm:ProvidedCHO rdf:about="http://some/url"/>
<ore:Aggregation rdf:about="http://some/url">
<...>
</ore:Aggregation>
<ore:Proxy rdf:about="http://some/url">
<...>
</ore:Proxy>
<edm:EuropeanaAggregation rdf:about="http://some/url">
<...>
</edm:EuropeanaAggregation>
</ore:aggregates>

<!--ITEM2 NODE-->
<ore:aggregates>
<...>
</ore:aggregates>

<!--ITEM3 NODE-->
<ore:aggregates>
<...>
</ore:aggregates>
</rdf:RDF>

预期结果

<!--ITEM 1-->
<rdf:RDF ...many namespaces...>
<edm:ProvidedCHO rdf:about="http://some/url"/>
<ore:Aggregation rdf:about="http://some/url">
<...>
</ore:Aggregation>
<ore:Proxy rdf:about="http://some/url">
<...>
</ore:Proxy>
<edm:EuropeanaAggregation rdf:about="http://some/url">
<...>
</edm:EuropeanaAggregation>
</rdf:RDF>


当前试用

尝试使用 lxml 应用一次逐项 XSLT(脚本+xslt)

from lxml import etree as ET
dom = ET.parse(source)
xslt = ET.parse(xsl_filename)
transform = ET.XSLT(xslt)
newdom = transform(dom)
print(ET.tostring(newdom, pretty_print=True))
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet exclude-result-prefixes="xsi xlink xml" version="2.0"
xmlns:many="namespaces">

<xsl:output encoding="UTF-8" indent="yes"/>

<!--<xsl:param name="output" select="'/Users/yep/Code/+dev/test data/output/'"/>-->
<xsl:param name="output" select="'/home/yep/data/split/'"/>
<xsl:param name="children" select="/rdf:RDF/ore:aggregates"/>

<!-- ROOT MATCH -->
<xsl:template match="/">
<xsl:for-each select="$children">
<xsl:call-template name="itemize"/>
</xsl:for-each>
</xsl:template>

<xsl:template name="itemize">

<xsl:variable name="uri" select="translate(ore:Proxy/dc:identifier, ' ', '_')"/>
<xsl:variable name="ns"/>
<xsl:variable name="fullOutput" select="concat($output, $uri)"/>
<xsl:result-document href="{$fullOutput}.xml" method="xml">
<xsl:element name="rdf:RDF">
<xsl:copy-of select="namespace::*"/>
<xsl:copy-of select="*"/>
</xsl:element>
</xsl:result-document>
</xsl:template>

</xsl:stylesheet>

...没有输出。也尝试过“写入”但不起作用

通过 ETree 尝试

import xml.etree.ElementTree as ET
root = ET.parse(source).getroot()

# namespaces variable generated from a json file
jsonFile = open("application/models/namespaces.json")
jsonStr = jsonFile.read()
namespaces = json.loads(jsonStr)

for item in root.findall("ore:aggregates",namespaces):
newTree = ET.parse("/home/yep/application/services/create/sample.xml")
newroot = newTree.getroot()

for node in item.findall("edm:ProvidedCHO",namespaces):
newroot.append(node)
ET.SubElement(newroot,node)

filename = "/home/yep/data/split/" + str(i) + ".xml"
newTree.write(filename)

TypeError: cannot serialize <Element '{http://www.europeana.eu/schemas/edm/}ProvidedCHO' at 0x7f4768a03688> (type Element)

我认为这个问题与我没有正确处理 namespace 有关,或者可能是因为当数据是Python时我仍然采用XSLT方法......一些帮助将不胜感激:)

最佳答案

由于您尝试使用 lxml 处理 XSLT,因此您只能使用 XSLT 1.0。由于 1.0 不支持 xsl:result-document,因此您必须使用 exlst document 扩展(幸运的是 lxml 支持)。

这是一个例子...

XML 输入 (test.xml)

<rdf:RDF xmlns:rdf="http://some rdf uri" xmlns:edm="http://some edm uri" xmlns:ore="http://some ore uri">
<!--ITEM1 NODE-->
<ore:aggregates>
<edm:ProvidedCHO rdf:about="http://some/url">from item1</edm:ProvidedCHO>
<ore:Aggregation rdf:about="http://some/url">from item1</ore:Aggregation>
<ore:Proxy rdf:about="http://some/url">from item1</ore:Proxy>
<edm:EuropeanaAggregation rdf:about="http://some/url">from item1</edm:EuropeanaAggregation>
</ore:aggregates>

<!--ITEM2 NODE-->
<ore:aggregates>
<edm:ProvidedCHO rdf:about="http://some/url">from item2</edm:ProvidedCHO>
<ore:Aggregation rdf:about="http://some/url">from item2</ore:Aggregation>
<ore:Proxy rdf:about="http://some/url">from item2</ore:Proxy>
<edm:EuropeanaAggregation rdf:about="http://some/url">from item2</edm:EuropeanaAggregation>
</ore:aggregates>

<!--ITEM3 NODE-->
<ore:aggregates>
<edm:ProvidedCHO rdf:about="http://some/url">from item3</edm:ProvidedCHO>
<ore:Aggregation rdf:about="http://some/url">from item3</ore:Aggregation>
<ore:Proxy rdf:about="http://some/url">from item3</ore:Proxy>
<edm:EuropeanaAggregation rdf:about="http://some/url">from item3</edm:EuropeanaAggregation>
</ore:aggregates>
</rdf:RDF>

XSLT 1.0(测试.xsl)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:strip-space elements="*"/>

<xsl:template match="/*/*">
<xsl:apply-templates select=".." mode="copy">
<xsl:with-param name="target_id" select="generate-id()"/>
</xsl:apply-templates>
</xsl:template>

<xsl:template match="/*" mode="copy">
<xsl:param name="target_id"/>
<exsl:document href="{$target_id}.xml" indent="yes">
<xsl:copy>
<xsl:copy-of select="@*|*[generate-id()=$target_id]/*"/>
</xsl:copy>
</exsl:document>
</xsl:template>

</xsl:stylesheet>

Python

from lxml import etree

tree = etree.parse("test.xml")
xslt = etree.parse("test.xsl")

tree.xslt(xslt)

输出(文件名基于生成的 ID,因此在运行我的代码时它们可能会有所不同。)

idm253366124.xml

<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://some_rdf_uri" xmlns:edm="http://some_edm_uri" xmlns:ore="http://some_ore_uri">
<edm:ProvidedCHO rdf:about="http://some/url">from item1</edm:ProvidedCHO>
<ore:Aggregation rdf:about="http://some/url">from item1</ore:Aggregation>
<ore:Proxy rdf:about="http://some/url">from item1</ore:Proxy>
<edm:EuropeanaAggregation rdf:about="http://some/url">from item1</edm:EuropeanaAggregation>
</rdf:RDF>

idm219411756.xml

<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://some_rdf_uri" xmlns:edm="http://some_edm_uri" xmlns:ore="http://some_ore_uri">
<edm:ProvidedCHO rdf:about="http://some/url">from item2</edm:ProvidedCHO>
<ore:Aggregation rdf:about="http://some/url">from item2</ore:Aggregation>
<ore:Proxy rdf:about="http://some/url">from item2</ore:Proxy>
<edm:EuropeanaAggregation rdf:about="http://some/url">from item2</edm:EuropeanaAggregation>
</rdf:RDF>

idm219410244.xml

<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://some_rdf_uri" xmlns:edm="http://some_edm_uri" xmlns:ore="http://some_ore_uri">
<edm:ProvidedCHO rdf:about="http://some/url">from item3</edm:ProvidedCHO>
<ore:Aggregation rdf:about="http://some/url">from item3</ore:Aggregation>
<ore:Proxy rdf:about="http://some/url">from item3</ore:Proxy>
<edm:EuropeanaAggregation rdf:about="http://some/url">from item3</edm:EuropeanaAggregation>
</rdf:RDF>
<小时/>

更新动态路径...

XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:rdf="http://some_rdf_uri" xmlns:edm="http://some_edm_uri"
xmlns:ore="http://some_ore_uri"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:strip-space elements="*"/>

<xsl:key name="elem_by_id" match="*" use="generate-id()"/>

<xsl:template match="/*" name="root">
<xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="*">
<xsl:apply-templates select="/*" mode="copy">
<xsl:with-param name="target_id" select="generate-id()"/>
</xsl:apply-templates>
</xsl:template>

<xsl:template match="/*" mode="copy">
<xsl:param name="target_id"/>
<exsl:document href="temp/{$target_id}.xml" indent="yes">
<xsl:copy>
<xsl:copy-of select="@*|key('elem_by_id',$target_id)/*"/>
</xsl:copy>
</exsl:document>
</xsl:template>

</xsl:stylesheet>

Python

from lxml import etree

tree = etree.parse("test.xml")
xslt = etree.parse("test.xsl")

target_path = "/rdf:RDF/ore:aggregates"

try:
elem = xslt.xpath("/xsl:stylesheet/xsl:template[@name='root']/xsl:apply-templates",
namespaces={"xsl": "http://www.w3.org/1999/XSL/Transform"})[0]
elem.attrib["select"] = target_path
except IndexError:
print("Could not find xsl:template to update.")

tree.xslt(xslt)

关于python - 在 Python 中逐项列出大型 xml 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54095195/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com