使用XSLT更改XML文件中的一个标记名称

时间:2010-04-04 02:55:15

标签: xml xslt

我是否可以在XSLT中使用条件,以便仅查找和替换特定标记名称的FIRST标记?

例如,我有一个包含许多<title>标记的XML文件。我想用<PageTitle>替换这些标签中的第一个。其余部分应该保持不变。我如何在变换中做到这一点?我现在拥有的是:

<xsl:template match="title">
     <PageTitle>
       <xsl:apply-templates />
     </PageTitle>
</xsl:template>

找到所有<title>个标记,并将其替换为<PageTitle>。任何帮助将不胜感激!

3 个答案:

答案 0 :(得分:4)

文档中的第一个title元素由

选择

<强> (//title)[1]

许多人错误地认为//title[1]选择了文档中的第一个title,这是一个经常犯的错误。 //title[1]选择每个title元素,该元素是其父级的第一个title子元素 - 而不是此处所需的元素。

使用此选项,以下转换将生成所需的输出

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

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

 <xsl:template match=
  "title[count(.|((//title)[1])) = 1]">

     <PageTitle>
       <xsl:apply-templates />
     </PageTitle>
 </xsl:template>
</xsl:stylesheet>

应用于此XML文档

<t>
 <a>
  <b>
    <title>Page Title</title>
  </b>
 </a>
 <b>
  <title/>
 </b>
 <c>
  <title/>
 </c>
</t>

生成了想要的结果

<t>
 <a>
  <b>
    <PageTitle>Page Title</PageTitle>
  </b>
 </a>
 <b>
  <title />
 </b>
 <c>
  <title />
 </c>
</t>

请注意我们如何在XPath 1.0中使用众所周知的Kaysian集合交集方法

如果有两个节点集$ns1$ns2,则以下表达式选择属于$ns1$ns2的每个节点:

<强> $ns1[count(.|$ns2) = count($ns2)]

在两个节点集仅包含一个节点且其中一个节点是当前节点的特定情况下,以下表达式在两个节点完全相同时精确计算为true()

<强> count(.|$ns2) = 1

在模板的匹配模式中使用此变体来覆盖标识规则:

<强> title[count(.|((//title)[1])) = 1]

仅匹配文档中的第一个title元素。

答案 1 :(得分:3)

这个应该有效:

<xsl:template match="title[1]">
     <PageTitle>
       <xsl:apply-templates />
     </PageTitle>
</xsl:template>

但它在每个上下文中都匹配第一个标题。因此,在以下示例中,/a/x/title[1]/a/title[1]都将匹配。因此,您可能需要指定match="/a/title[1]"

之类的内容
<a>
    <x>
        <title/> <!-- first title in the context -->
    </x>
    <title/> <!-- first title in the context -->
    <title/>
    <c/>
    <title/>
</a>

答案 2 :(得分:3)

如果所有标题标签都是兄弟标签,您可以使用:

<xsl:template match="title[1]">
    <PageTitle>
        <xsl:apply-templates />
    </PageTitle>
</xsl:template> 

但是,这将匹配作为任何节点的第一个子节点的所有title元素。如果标题可能具有不同的父节点,并且您只希望将整个文档中的第一个标题替换为PageTitle,则可以使用

<xsl:template match="title[not(preceding::title or ancestor::title)]">
    <PageTitle>
        <xsl:apply-templates />
    </PageTitle>
</xsl:template>