代码之家  ›  专栏  ›  技术社区  ›  AlbertoPL

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

  •  3
  • AlbertoPL  · 技术社区  · 16 年前

    我是否可以在XSLT中使用条件,以便只查找和替换特定标记名的第一个标记?

    例如,我有一个XML文件,其中包含许多 <title> 标签。我想把这些标签中的第一个换成 <PageTitle> . 剩下的应该一个人呆着。在我的转换过程中,我将如何做到这一点?我现在拥有的是:

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

    找到所有 <标题> 标记并替换为 <PigeTyt & GT; .任何帮助都将不胜感激!

    3 回复  |  直到 16 年前
        1
  •  4
  •   Dimitre Novatchev    16 年前

    第一 title 文档中的元素由选择 :

    (//title)[1]

    很多人错误地认为 //title[1] 选择第一个 标题 在文档中,这是一个经常犯的错误。 //标题[ 1 ] 选择每一个 标题 第一个元素 标题 它的父母的孩子——不是这里想要的。

    使用这个,下面的转换将生成所需的输出 :

    <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]

    只匹配第一个 标题 文档中的元素。

        2
  •  3
  •   Krab    16 年前

    这个应该有效:

    <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>
    
        3
  •  3
  •   markusk Kiril Kirilov    16 年前

    如果所有的标题标签都是同级的,则可以使用:

    <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>