XSLT-1.0:如何在相对于父元素的特定位置插入元素

时间:2017-04-12 02:48:40

标签: xml xslt xslt-1.0

我试图找出子元素相对于其父元素的位置 我有以下输入XML:

<Begin>
    <tag1>g</tag1>
    <tag2>b</tag2>
    <tag3>c</tag3>
    <tag5>e</tag5>
</Begin>

我需要知道<tag3>相对于<Begin>的位置,即3

这可以在XSLT中完成吗? 我目前的XSLT看起来像这样:

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

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

  <xsl:template match="Begin[count(tag4)=0]">
    <xsl:copy>
      <!-- Need to find the position of /Begin/tag3" here -->
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

基本上,我要做的是在输入XML中找到<tag3>的位置 并使用职位在<tag4>之后插入<tag3>

所以我的问题是:
如何在<tag4><tag3>之间的位置插入元素<tag5>? 这是我的意图!

4 个答案:

答案 0 :(得分:1)

按字母顺序排序新元素的简单方法是在身份模板中使用<xsl:sort>,如下所示:

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

此修改会复制由local-name / tag-name / element-name按字母顺序排序的所有元素。

答案 1 :(得分:0)

您可以使用xsl:numbercount(preceding-sibling::*)找出孩子的位置。

但这对问题的下一部分没有帮助:insert <tag4> exactly after <tag3> using the position。在XSLT中,您始终将新数据添加到结果树中的当前写入位置,您无法将其添加到特定位置。所以我认为我们需要知道你真正想要实现的目标,而不是你提出的实现方法。

答案 2 :(得分:0)

您不需要知道节点的位置,以便在其之后(或之前)插入另一个节点。在您给出的示例中,您可以使用:

<强> XSLT

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

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

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

</xsl:stylesheet>

返回:

<?xml version="1.0" encoding="UTF-8"?>
<Begin>
    <tag1>g</tag1>
    <tag2>b</tag2>
    <tag3>c</tag3>
    <tag4>d</tag4>
    <tag5>e</tag5>
</Begin>

当然,如果提供的输入中没有tag3元素,则不会发生任何事情。如果有多个,则在每个元素之后插入新元素。

答案 3 :(得分:0)

就像我的评论中提到的,与@ michael.hor257k的答案非常相似,不是检查位置,只需将匹配更改为Begin[not(tag4)]/tag3,然后输出tag3和新的tag4 ...

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

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

  <xsl:template match="Begin[not(tag4)]/tag3">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
    <tag4>d</tag4>
  </xsl:template>
</xsl:stylesheet>
  

嗨@ DanielHaley- :)实际上有效。但只是好奇......我们怎么样   找到tag3的位置w.r.t开始?

如果您使用的是XSLT 2.0,则可以使用<xsl:number select="tag3" count="*"/>(1.0不允许xsl:number上的select元素。

在1.0中,您可以使用使用xsl:numbercount(preceding-sibling::*)的模式模板(正如@ michael-kay所建议的那样)......

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

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

  <xsl:template match="Begin[not(tag4)]">
    <xsl:copy>
      <!-- Need to find the position of /Begin/tag3" here -->
      <xsl:apply-templates select="tag3" mode="getPos"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*" mode="getPos">
    <xsl:number count="*"/>
    <!-- alternative to xsl:number:
    <xsl:value-of select="count(preceding-sibling::*) + 1"/>
    -->
  </xsl:template>

</xsl:stylesheet>

输出结果为:

<Begin>3</Begin>