【问题标题】:Problem inserting node (text) into XML document via XSLT通过 XSLT 将节点(文本)插入 XML 文档时出现问题
【发布时间】:2010-06-10 04:11:08
【问题描述】:

当满足某个条件到使用 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 中的每个节点(有时甚至不在节点下)时出现奇怪的行为。另外,我在跳过节点时遇到问题,因此可以将节点插入到项目中,而不是直接在 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 中缺少什么?或者,有没有更好的方法来解决这个问题?

谢谢。

【问题讨论】:

  • 好问题 (+1)。请参阅我的答案以获得完整的解决方案。

标签: xml xslt


【解决方案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>

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

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

【讨论】:

  • 是的,我在发完这篇文章后仍在努力。我接近你所拥有的。我在 add-new-step1-stuff 中有一个额外的应用模板,另一个应用模板在错误的位置,所以在 5 位 xml 文件中看起来有点奇怪。奇怪的是我没有使用
【解决方案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="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>

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多