我有一个从股票系统输出的XML文档,它的结构不是特别好:
<root>
<StockSalesRec Type="SH">
<Reference>A Supplier</Reference>
<StockNum></StockNum>
<Description></Description>
...
</StockSalesRec>
<StockSalesRec Type=" ">
<Reference>12345</Reference>
<StockNum>00001</StockNum>
<Description>Item description</Description>
...
</StockSalesRec>
<StockSalesRec Type=" ">
<Reference>67890</Reference>
<StockNum>00002</StockNum>
<Description>Another description</Description>
...
</StockSalesRec>
...
</root>
每个<StockSalesRec Type=SH>
都是一个供应商,下一个<StockSalesRec Type=SH>
之前的所有东西都是该供应商的产品。在使用这个文档之前,我想重新构造它,使它看起来像:
<root>
<supplier name="A Supplier">
<product>
<Reference>67890</Reference>
<StockNum>00002</StockNum>
<Description>Another description</Description>
</product>
....
</supplier>
....
</root>
我该如何以这种方式转换文档呢?我曾尝试使用XSL作为解决方案,但是很快就卡住了。我最近正在学习Ruby,所以使用这些解决方案会很好。
谢谢
我认为这可以用一个纯XSLT解决方案来完成。我首先为每个产品定义一个键(一个StockSalesRec, 类型为' '),其中查找是最近的前供应商记录的引用(一个StockSalesRec, 类型为'SH')
<xsl:key
name="Stock"
match="StockSalesRec[@Type=' ']"
use="(preceding-sibling::StockSalesRec[@Type='SH'])[last()]/Reference" />
你可以像这样匹配每个供应商节点
<xsl:apply-templates select="StockSalesRec[@Type='SH']" />
然后对于每个这样的供应商节点,您可以使用前面定义的键读取所有Product记录
<xsl:apply-templates select="key('Stock', Reference)" />
把这些放在一起得到....
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key
name="Stock"
match="StockSalesRec[@Type=' ']"
use="(preceding-sibling::StockSalesRec[@Type='SH'])[last()]/Reference"/>
<xsl:template match="/root">
<xsl:copy>
<xsl:apply-templates select="StockSalesRec[@Type='SH']"/>
</xsl:copy>
</xsl:template>
<xsl:template match="StockSalesRec[@Type='SH']">
<supplier name="{Reference}">
<xsl:apply-templates select="key('Stock', Reference)"/>
</supplier>
</xsl:template>
<xsl:template match="StockSalesRec[@Type=' ']">
<product>
<xsl:apply-templates/>
</product>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
当您将此应用于示例XML时,输出如下:
<root>
<supplier name="A Supplier">
<product>
<Reference>12345</Reference>
<StockNum>00001</StockNum>
<Description>Item description</Description>
</product>
<product>
<Reference>67890</Reference>
<StockNum>00002</StockNum>
<Description>Another description</Description>
</product>
</supplier>
</root>
请注意,在创建产品节点时使用了标识转换,允许将额外的子元素添加到输入XML中,而无需更改XSLT。