通过XSLT将节点(文本)插入XML文档时出现问题

时间:2010-06-10 04:11:08

标签: xml xslt

当使用XSLT将某个条件满足到xml文档时,我无法插入文本块。假设我有以下xml:

<oldStep Name="Step1">
    <oldItems>
        <oldItem ItemName="item1">
        </oldItem>
        <!-- want to add an extra <Item> here if Step Name == "Step1" -->
        <oldItem ItemName="Step1item">
        </oldItem>
    </oldItems>
</oldStep>
<oldStep Name="Step2">
    <oldItems>
       ...
    </oldItems>
</oldStep>

在旧节点名称转换为新节点名称的过程中,每当oldStep Name等于某个值(在本例中为Step1)时,我想添加一个额外的文本块(或手动构造的节点)。我尝试使用下面的XSLT,但最后有一个奇怪的行为,即在匹配时将文本块添加到xml中的每个节点(有时甚至不在节点下)。另外,我在跳过节点时遇到问题,因此可以在Items中插入节点,而不是直接在oldStep下插入:

<xsl:template match="oldItems">
    <xsl:element name="Item">
        <xsl:if test="../@Name = 'Step1'>
            <xsl:call-template name = "identity"></xsl:call-template>
        </xsl:if>
        <xsl:apply-templates />
    </xsl:element>
</xsl:template>

<xsl:template match="node()" name="identity">
    <xsl:element name="Item">
        <xsl:attribute name="ItemName">Step1item</xsl:attribute>
        </xsl:apply-templates />
    </xsl:element>
</xsl:template>

我觉得我的条件不对,但谷歌搜索没有真正的帮助(搜索字符串太模糊)。我在xsl中缺少什么?或者,有没有更好的方法解决这个问题?

感谢。

3 个答案:

答案 0 :(得分:1)

此转化

<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="oldStep[@Name='Step1']/*/oldItem[1]">
  <xsl:call-template name="identity"/>

  <Item ItemName='Step1item'/>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档

<steps>
    <oldStep Name="Step1">
        <oldItems>
            <oldItem ItemName="item1"/>
            <!-- want to add an extra <Item> here if Step Name == "Step1" -->
            <oldItem ItemName="Step1item"/>
        </oldItems>
    </oldStep>
    <oldStep Name="Step2">
        <oldItems>
       ...
        </oldItems>
    </oldStep>
</steps>

产生想要的结果

<steps>
   <oldStep Name="Step1">
      <oldItems>
         <oldItem ItemName="item1"/>
         <Item ItemName="Step1item"/><!-- want to add an extra <Item> here if Step Name == "Step1" -->
         <oldItem ItemName="Step1item"/>
      </oldItems>
   </oldStep>
   <oldStep Name="Step2">
      <oldItems>
       ...
        </oldItems>
   </oldStep>
</steps>

答案 1 :(得分:1)

名为“identity”的模板与任何节点匹配,因此会将其应用于它处理的每个节点。不要把它与任何东西相匹配。

答案 2 :(得分:1)

您的描述有点难以理解。以下是我解释您的问题的方法:

  

给我一​​个默认复制一切的变压器,除了:

     
      
  • 它将oldItem元素转换为Item元素   
  • 它在“步骤1”下的oldItems元素中添加了一个额外的项目,作为最后一个元素   

这是一个解决方案:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <!-- by default, copy everything -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  <!-- special handling for old items -->
  <xsl:template match="oldItems">
    <!-- transform all old items first -->
    <xsl:apply-templates select="@*|node()"/>
    <xsl:if test="../@Name = 'Step1'">
      <xsl:call-template name="add-new-step1-stuff"/>
    </xsl:if>
  </xsl:template>
  <!-- add new step 1 stuff -->
  <xsl:template name="add-new-step1-stuff">
    <xsl:element name="Item">
      <xsl:attribute name="ItemName">Step1item</xsl:attribute>
    </xsl:element>
  </xsl:template>
  <!-- converts each oldItem to Item -->
  <xsl:template match="oldItem"> 
    <xsl:element name="Item">
      <xsl:apply-templates select="@*|node()"/>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

,当应用于:

<?xml version="1.0" encoding="utf-8"?>
<oldSteps>
  <oldStep Name="Step1">
    <oldItems>
      <oldItem ItemName="item1"></oldItem>
    </oldItems>
  </oldStep>
  <oldStep Name="Step2">
    <oldItems>
      <oldItem ItemName="item2"></oldItem>
      <oldItem ItemName="item3"></oldItem>
    </oldItems>
  </oldStep>
</oldSteps>

(不完全是你给的,但我认为你的意思)

的产率:

<?xml version="1.0"?>
<oldSteps>
  <oldStep Name="Step1">

      <Item ItemName="item1"/>
    <Item ItemName="Step1item"/>
  </oldStep>
  <oldStep Name="Step2">

      <Item ItemName="item2"/>
      <Item ItemName="item3"/>

  </oldStep>
</oldSteps>

需要一些空白清理,但我认为是你正在寻找的结构。

如果你想要块文本而不是额外的项目,你只需要像这样重写add-new-step1-stuff模板:

<!-- add new step 1 stuff -->
<xsl:template name="add-new-step1-stuff">
  <xsl:text>
    Here's some block text that goes at the end.
  </xsl:text>
</xsl:template>

我的样式表和你的样式表之间的主要区别:

  • 您的身份(默认复制)转换适用于文档中的每个节点,并生成一个项目,您正在其中复制其余内容 - 这就是为什么您要这样做的原因看到各处的物品!在我的身份中,身份变换和元素的添加是分开的。请注意,如果在适当的位置添加apply-templates,则不需要显式调用标识转换。
  • 您的转换缺少复制属性,我想您想要保留这些属性。
  • 您的转换将在第1步下面的oldItems中的每个oldItem之后添加一个Item,我也想象这不是您想要的。