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() < last()">
<xsl:value-of select="$delimiter" />
</xsl:if>
</xsl:for-each>
<xsl:text>
 </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() < last()">
<xsl:value-of select="$delimiter" />
</xsl:if>
</xsl:for-each>
<xsl:if test="position() < last()">
<xsl:text>
 </xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
上記の XSLT は、機能の観点から非常にうまく機能します。しかし、私はこれを約10000レコードを処理しようとしています。つまり、sObject 要素の 10000 インスタンスには、各 sObject の下に約 15 のフィールドが含まれます。
これらの多くのレコードを処理するために XSLT の上でこれを実行すると、トスになります。XSLT の処理と csv データの提供には約 20 分かかります。これを数秒で終わらせたかったのです。つまり、XSLT は 10,000 レコード (sObject エントリ) を処理して上記のように有効な CSV データを取得するのに 3 ~ 4 秒かかります。
これは、私が XSLT を拡張するのに行き詰まっており、この XSLT をより高速に動作させるために変更するのに助けが必要な場所です。