如何基于邻近节点的兄弟节点重构这个xml文档



我有一个从股票系统输出的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。

相关内容

  • 没有找到相关文章

最新更新