XSLT在特定位置添加缺少的节点

时间:2015-12-14 12:19:16

标签: xml xslt

我想将缺少的节点插入XML,以防它丢失。例如,我想在CustomInformation节点之前添加<Details>节点。我编写了下面的XSLT转换,但CostPlan节点上的属性没有出现。我哪里错了?

示例数据:

<CostPlan code="test" periodType="MONTHLY" >
    <Description/>
    <GroupingAttributes>
        <GroupingAttribute>cost_type_id</GroupingAttribute>
        <GroupingAttribute>transaction_class_id</GroupingAttribute>
        <GroupingAttribute>charge_code_id</GroupingAttribute>
    </GroupingAttributes>

    <CustomInformation>
        <ColumnValue name="pra">xyz</ColumnValue>
        <ColumnValue name="partition_code">abc</ColumnValue>
    </CustomInformation>
</CostPlan>

XSLT转型:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="CostPlan[not(Details)]">
         <xsl:variable name="elements-after" select="CustomInformation"/>
      <xsl:copy>
          <xsl:copy-of select="* except $elements-after"/>
          <Details/>
          <xsl:copy-of select="$elements-after"/>
        </xsl:copy>
      </xsl:template>
</xsl:stylesheet>

输出:

<CostPlan> <!-- attributes missing compared to original  -->
   <Description/>
   <GroupingAttributes>
      <GroupingAttribute>cost_type_id</GroupingAttribute>
      <GroupingAttribute>transaction_class_id</GroupingAttribute>
      <GroupingAttribute>charge_code_id</GroupingAttribute>
   </GroupingAttributes>
   <Details/>
   <CustomInformation>
      <ColumnValue name="pra">xyz</ColumnValue>
      <ColumnValue name="partition_code">abc</ColumnValue>
   </CustomInformation>
</CostPlan>

2 个答案:

答案 0 :(得分:3)

嗯,匹配CostPlan[not(Details)]的模板不处理属性。变化:

<xsl:copy-of select="* except $elements-after"/>

为:

<xsl:copy-of select="@* | * except $elements-after"/>

另请注意,您的样式表标记为XSLT 1.0,但您肯定使用的是XSLT 2.0。

在XSLT 1.0中你可以这样做:

<xsl:template match="CostPlan[not(Details)]">
    <xsl:copy>
        <xsl:copy-of select="@* | *[not(self::CustomInformation)]"/>
        <Details/>
        <xsl:copy-of select="CustomInformation"/>
    </xsl:copy>
</xsl:template>

请注意,$elements-after变量仅使用一次,因此是多余的(在两个版本中)。

答案 1 :(得分:2)

更短更简单

<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

  <xsl:template match="CostPlan[not(Details)]/CustomInformation">
    <Details/>
    <xsl:call-template name="identity"/>
  </xsl:template>
</xsl:stylesheet>