Changing the name of a single tag in an XML file using XSLT

Is it possible for me to have a condition in XSLT to find and replace only the FIRST tag of a specific tag name?

For example, I have an XML file with many tags <title>. I would like to replace the first of these tags with <PageTitle>. The rest must be left alone. How can I do this in my conversion? What I have now:

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

which finds all tags <title>and replaces them <PageTitle>. Any help would be greatly appreciated!

+3
source share
3 answers

The first element titlein the document is selected :

(//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:

$ns1 $ns2, node, $ns1, $ns2:

$ns1[count(.|$ns2) = count($ns2)]

, node -sets node, node, true(), :

count(.|$ns2) = 1

, :

title[count(.|((//title)[1])) = 1]

title .

+4

:

<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

, :

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

However, this will match all elements titlethat are the first descendant of any node. If the headers can have different parent nodes, and you want the first title of the entire document to be replaced with PageTitle, you can use

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

Source: https://habr.com/ru/post/1739733/


All Articles