gpt4 book ai didi

xml - 高速 XSLT 将 XML 转换为 CSV

转载 作者:数据小太阳 更新时间:2023-10-29 01:53:18 24 4
gpt4 key购买 nike

我一直在尝试使用 XSLT 在最有效的时间内从 XML 文档获取 CSV 数据。以下是我的示例 XML

<?xml version="1.0" encoding="ISO-8859-1"?>
<sObjects xmlns="urn:sobject.partner.soap.sforce.com">
<sObject>
<Name>Raagu</Name>
<BillingStreet>Hoskote</BillingStreet>
</sObject>
<sObject>
<Name>Rajath</Name>
<BillingStreet>BTM</BillingStreet>
<age>25</age>
</sObject>
<sObject>
<Name>Sarath</Name>
<BillingStreet>Murgesh</BillingStreet>
<location>Bangalore</location>
<age>#N/A</age>
</sObject>
<sObject>
<Name>Bharath</Name>
<BillingStreet>EGL</BillingStreet>
<location>Bangalore</location>
<shipping>Hoskote</Shipping>
</sObject>
<sObject>
<Id>12312321321</Id>
<Name>Guru</Name>
<location>Sirsi</location>
<date>12-12-12</date>
</sObject>
<sObject>
<Name>Appa</Name>
<BillingStreet>someStrrt</BillingStreet>
<accountNo>213213</accountNo>
</sObject>
<sObject>
<Name>Sarath</Name>
<BillingStreet>Murgesh</BillingStreet>
<location>Bangalore</location>
</sObject>
<sObject>
<Name>Sarath</Name>
<BillingStreet>Murgesh</BillingStreet>
<location>Bangalore</location>
</sObject>
<sObject>
<Name>Sarath</Name>
<BillingStreet>Murgesh</BillingStreet>
<location>Bangalore</location>
</sObject>

我想要这种输出

 <?xml version="1.0" encoding="utf-8"?><csv xmlns="http://www.approuter.com/schemas/RootNode"><data>Name,BillingStreet,age,location,Shipping,Id,date,accountNo
Raagu,Hoskote,,,,,,
Rajath,BTM,25,,,,,
Sarath,Murgesh,#N/A,Bangalore,,,,
Bharath,EGL,,Bangalore,Hoskote,,,
Guru,,,Sirsi,,12312321321,12-12-12,
Appa,someStrrt,,,,,,213213
Sarath,Murgesh,,Bangalore,,,,
Sarath,Murgesh,,Bangalore,,,,
Sarath,Murgesh,,Bangalore,,,,</data></csv>

为了完成这项工作,我尝试遵循 XSLT

<xsl:stylesheet version="1.0" xmlns:p0="urn:sobject.partner.soap.sforce.com" xmlns:csv="csv:csv" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="utf-8" method="xml"/>
<xsl:strip-space elements="*" />
<xsl:variable name="delimiter" select="','"/>

<xsl:key name="field" match="p0:sObject/*" use="name()"/>

<!-- variable containing the first occurrence of each field -->
<xsl:variable name="allFields"
select="/*/*/*[generate-id()=generate-id(key('field', name())[1])]"/>

<xsl:template match="/">
<!-- Output the CSV header -->
<xsl:element name="csv" namespace="http://www.approuter.com/schemas/RootNode">
<xsl:element name="data" namespace="http://www.approuter.com/schemas/RootNode">

<xsl:for-each select="$allFields">
<xsl:value-of select="name()" />
<xsl:if test="position() &lt; last()">
<xsl:value-of select="$delimiter" />
</xsl:if>
</xsl:for-each>

<xsl:text>&#xa; </xsl:text>

<xsl:apply-templates select="/*/p0:sObject" />

</xsl:element>
</xsl:element>

</xsl:template>

<xsl:template match="p0:sObject">
<xsl:variable name="this" select="." />
<xsl:for-each select="$allFields">
<xsl:value-of select="$this/*[name() = name(current())]" />
<xsl:if test="position() &lt; last()">
<xsl:value-of select="$delimiter" />
</xsl:if>
</xsl:for-each>
<xsl:if test="position() &lt; last()">
<xsl:text>&#xa; </xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

从功能分析的角度来看,上面的 XSLT 工作得很好。但我正在尝试处理大约 10000 条记录。即 sObject 元素上的 10000 个实例,每个 sObject 将在其下包含大约 15 个字段。

如果我在XSLT上面运行这个来处理这么多记录,那就要折腾了。 XSLT 大约需要 20 分钟来处理和提供 csv 数据。我想在几秒钟内完成这件事。也就是说,XSLT 应该花费 3-4 秒来处理 10k 条记录(sObject 条目)以提供有效的 CSV 数据,如上所示。

这是我坚持增强 XSLT 的地方,需要帮助修改此 XSLT 以更快地工作。

最佳答案

我觉得这是一道难题。我没有看到任何明显的东西。使用多步构建是诀窍:我创建了 pass1.xsl 和 pass2.xsl,它们大大创建了输出树。

我制作了一个树大小为 252097 个节点(697768 个字符)的测试文件。您的 XSL 花费了 21 秒,而下面的两个 xsls 花费了几秒钟。

传递 1 个 XSL

<xsl:stylesheet version="2.0" xmlns:p0="urn:sobject.partner.soap.sforce.com" 
xmlns:csv="csv:csv" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="utf-8" method="xml" indent="no"/>
<xsl:strip-space elements="*" />
<xsl:variable name="delimiter" select="','"/>

<xsl:variable name="allFields">
<xsl:for-each select="distinct-values( /*/*/*/name() )">
<xsl:element name="{.}" />
</xsl:for-each>
</xsl:variable>

<xsl:template match="p0:sObjects">
<xsl:element name="{local-name(.)}" namespace="urn:sobject.partner.soap.sforce.com">
<xsl:element name="order" namespace="urn:sobject.partner.soap.sforce.com">
<xsl:for-each select="$allFields/*">
<xsl:value-of select="name()" />
<xsl:if test="position() &lt; last()">
<xsl:value-of select="$delimiter" />
</xsl:if>
</xsl:for-each>
</xsl:element>

<xsl:apply-templates select="/*/p0:sObject" />
</xsl:element>
</xsl:template>

<xsl:template match="p0:sObject">
<xsl:variable name="this" select="." />
<xsl:element name="{local-name(.)}" namespace="urn:sobject.partner.soap.sforce.com">
<xsl:for-each select="$allFields/*">
<xsl:element name="{local-name(.)}" namespace="urn:sobject.partner.soap.sforce.com">
<xsl:value-of select="$this/*[name() = name(current())]" />
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

传递 2 XSL

<xsl:stylesheet version="2.0" xmlns:p0="urn:sobject.partner.soap.sforce.com" 
xmlns:csv="csv:csv" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="utf-8" method="xml" indent="no"/>
<xsl:strip-space elements="*" />
<xsl:variable name="delimiter" select="','"/>

<xsl:template match="/">
<xsl:element name="csv" namespace="http://www.approuter.com/schemas/RootNode">
<xsl:element name="data" namespace="http://www.approuter.com/schemas/RootNode">
<xsl:apply-templates select="/p0:sObjects/*" />
</xsl:element>
</xsl:element>
</xsl:template>

<xsl:template match="p0:order">
<xsl:value-of select="." />
</xsl:template>

<!-- use Michael's suggestion about using first instead of last() -->
<xsl:template match="p0:sObject/*[ position() = 1 ]">
<xsl:text>&#xa; </xsl:text>
<xsl:value-of select="." />
</xsl:template>

<xsl:template match="p0:sObject/*[ position() > 1 ]">
<xsl:value-of select="$delimiter" />
<xsl:value-of select="." />
</xsl:template>
</xsl:stylesheet>

通过 1 输出

这是第 1 步的输出 xml。这将创建一个如下所示的 xml(更容易为下一阶段解析。看到 sObject 下的新空元素了吗?):

<sObjects xmlns="urn:sobject.partner.soap.sforce.com">
<order>Name,BillingStreet,age,location,shipping,Id,date,accountNo</order>
<sObject>
<Name>Raagu</Name>
<BillingStreet>Hoskote</BillingStreet>
<age/>
<location/>
<shipping/>
<Id/>
<date/>
<accountNo/>
</sObject>
</xObjects>

最后,结果:

<csv xmlns="http://www.approuter.com/schemas/RootNode"><data>Name,BillingStreet,age,location,shipping,Id,date,accountNo
Raagu,Hoskote,,,,,,
Rajath,BTM,25,,,,,
...

我执行的命令:

saxonb-xslt -t bigxml.xml pass1.xsl > intermediate.xml
saxonb-xslt -t intermediate.xml pass2.xsl > res.xml

关于xml - 高速 XSLT 将 XML 转换为 CSV,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15231889/

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