XSLT根据子节点的出现转换子节点名称

时间:2014-04-22 10:05:43

标签: xml xslt xslt-1.0

这是我的要求我需要编写一个XSLT来根据出现的情况转换节点名称看看我的例子

XML现在:

<Orders>
    <Order>
        <OrderNo>ABC</OrderNo>
        <ItemDetails>
            <Name>Shirt</Name>
            <Name>Socks</Name>
            <ItemPrice>30</ItemPrice>
            <ItemPrice>40</ItemPrice>
        </ItemDetails>
    </Order>
</Orders>

需要XML

<Orders>
    <Order>
        <OrderNo>ABC</OrderNo>
        <ItemDetails>
            <Name1>Shirt</Name>
            <Name2>Socks</Name>
            <ItemPrice1>30</ItemPrice>
            <ItemPrice2>40</ItemPrice>
        </ItemDetails>
    </Order>
</Orders>

检查名称和项目价格风险。像这样我在一个xml的ORDERS中有100个订单

1 个答案:

答案 0 :(得分:1)

这可以使用基于身份转换的样式表来复制大部分未更改的XML,只需调整您想要更改的小位:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:template match="@*|node()">
    <xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy>
  </xsl:template>

  <xsl:template match="ItemDetails/*">
    <xsl:element name="{name()}{count(
            preceding-sibling::*[name() = name(current())]) + 1}">
      <xsl:apply-templates select="@*|node()" />
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

如果你想单独留下每个元素的第一个,并从第二个开始编号,那么你可以通过调整模板匹配模式在XSLT 2.0中做到这一点:

  <xsl:template match="ItemDetails/*[preceding-sibling::*[name() = name(current())]]">
    <xsl:element name="{name()}{count(
            preceding-sibling::*[name() = name(current())])}">
      <xsl:apply-templates select="@*|node()" />
    </xsl:element>
  </xsl:template>

但是在XSLT 1.0中,你不能在current()模式中使用match,所以你必须在模板体内进行检查,例如。

  <xsl:template match="@*|node()" name="ident">
    <xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy>
  </xsl:template>

  <xsl:template match="ItemDetails/*">
    <xsl:choose>
      <xsl:when test="preceding-sibling::*[name() = name(current())]">
        <xsl:element name="{name()}{count(
            preceding-sibling::*[name() = name(current())])}">
          <xsl:apply-templates select="@*|node()" />
        </xsl:element>
      </xsl:when>
      <xsl:otherwise>
        <!-- this is the first element with this name, so revert to the
             identity behaviour -->
        <xsl:call-template name="ident" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

在更一般的层面上,这是一种相当糟糕的XML格式选择 - 对于表示相同类型数据的元素使用相同的名称更为常见,并且通过嵌套而不是定位来表达不同元素之间的依赖关系,例如

<ItemDetails>
    <Item>
        <Name>Shirt</Name>
        <Price>30</Price>
    </Item>
    <Item>
        <Name>Socks</Name>
        <Price>40</Price>
    </Item>
</ItemDetails>