In the following code, I need, in the place of the two xxxx's, to have the name of the element (name()), so h1, h2 or h3, whatever the match may be. So the second xxxx must be the count of the h1/h2/h3 in that file. The attribute will then look like "h1_4", or h3_15" etc.
How do I do that ?
<xsl:template match="h1[not(#id)] | h2[not(#id)] | h3[not(#id)]" >
<xsl:element name="{name()}" >
<xsl:attribute name="id">xxxx_<xsl:value-of><xsl:number count="xxxx" /></xsl:value-of></xsl:attribute>
</xsl:element>
<xsl:apply-templates/>
</xsl:template>
As I said, the request is ambiguous. The following stylesheet:
XSLT 1.0
<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="h1[not(#id)] | h2[not(#id)] | h3[not(#id)]" >
<xsl:variable name="name" select="name()" />
<xsl:copy>
<xsl:attribute name="id">
<xsl:value-of select="$name"/>
<xsl:text>_</xsl:text>
<xsl:value-of select="count(preceding::*[name()=$name]) + 1"/>
</xsl:attribute>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
when applied to the following test input:
<root>
<h1 id="h1_1"/>
<h2 type="abc"/>
<h3 type="xyz"/>
<h1>content</h1>
<h3 id="h3_2" type="efg"/>
<h2/>
</root>
will produce:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<h1 id="h1_1"/>
<h2 id="h2_1" type="abc"/>
<h3 id="h3_1" type="xyz"/>
<h1 id="h1_2">content</h1>
<h3 id="h3_2" type="efg"/>
<h2 id="h2_2"/>
</root>
You're on the right track using xsl:number, how about:
<xsl:template match="h1 | h2 | h3" >
<xsl:copy>
<xsl:attribute name="id">
<xsl:value-of select="name()"/>
<xsl:text>_</xsl:text>
<xsl:number level="any" />
</xsl:attribute>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
I'm assuming an identity template to copy the rest of the document as-is, and that being the case I've simplified the match pattern - you don't need to check for not(#id) as where there is an id attribute in the input it will overwrite the one being created by the xsl:attribute.
Related
I have an xml as below:
<?xml version="1.0" encoding="UTF-8"?>
<mdb:MD_Metadata xmlns:mdb="http://standards.iso.org/iso/19115/-3/mdb/1.0"
xmlns:cit="http://standards.iso.org/iso/19115/-3/cit/1.0"
xmlns:lan="http://standards.iso.org/iso/19115/-3/lan/1.0"
xmlns:mcc="http://standards.iso.org/iso/19115/-3/mcc/1.0"
xmlns:gco="http://standards.iso.org/iso/19115/-3/gco/1.0">
<mdb:metadataIdentifier>
<mcc:MD_Identifier>
<mcc:authority>
<cit:CI_Citation>
<cit:title>
<gco:CharacterString>Old UUID</gco:CharacterString>
</cit:title>
</cit:CI_Citation>
</mcc:authority>
<mcc:code>
<gco:CharacterString>3796749d-c8a5-46ae-af11-24a977cb1d9a</gco:CharacterString>
</mcc:code>
<mcc:codeSpace>
<gco:CharacterString>urn:uuid</gco:CharacterString>
</mcc:codeSpace>
</mcc:MD_Identifier>
</mdb:metadataIdentifier>
</mdb:MD_Metadata>
I want to update the namespaces (mdb and cit to2.0) before applying other templates:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:cit1="http://standards.iso.org/iso/19115/-3/cit/1.0"
xmlns:cit="http://standards.iso.org/iso/19115/-3/cit/2.0"
xmlns:lan="http://standards.iso.org/iso/19115/-3/lan/1.0"
xmlns:mcc="http://standards.iso.org/iso/19115/-3/mcc/1.0"
xmlns:mco="http://standards.iso.org/iso/19115/-3/mco/1.0"
xmlns:mda="http://standards.iso.org/iso/19115/-3/mda/1.0"
xmlns:mdb1="http://standards.iso.org/iso/19115/-3/mdb/1.0"
xmlns:mdb="http://standards.iso.org/iso/19115/-3/mdb/2.0"
xmlns:gco="http://standards.iso.org/iso/19115/-3/gco/1.0"
xmlns:gcx="http://standards.iso.org/iso/19115/-3/gcx/1.0"
xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
exclude-result-prefixes="#all">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="mdb1:*">
<xsl:element name="{name()}" namespace="http://standards.iso.org/iso/19115/-3/mdb/2.0">
<xsl:if test="count(ancestor::*) = 0">
<xsl:call-template name="add-iso19115-3.2018-namespaces"/>
</xsl:if>
</xsl:element>
</xsl:template>
<xsl:template match="cit1:*" >
<xsl:element name="{name()}" namespace="http://standards.iso.org/iso/19115/-3/cit/2.0">
<xsl:apply-templates select="#*|*"/>
</xsl:element>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<!--Identity template that will copy every attribute, element, comment, and processing instruction to the output-->
<xsl:template match="#*|node()">
<xsl:copy copy-namespaces="no">
<!-- Including any attributes it has and any child nodes -->
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="mdb:MD_Metadata" mode="main">
<xsl:copy>
<xsl:apply-templates select="#* , node()"/>
<!-- add mdb:defaultLocale after mdb:metadataIdentifier -->
<mdb:defaultLocale>
<lan:PT_Locale id="EN">
<lan:language>
<lan:LanguageCode codeList="http://www.loc.gov/standards/iso639-2/" codeListValue="eng"/>
</lan:language>
<lan:characterEncoding>
<lan:MD_CharacterSetCode codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#MD_CharacterSetCode" codeListValue="utf8"/>
</lan:characterEncoding>
</lan:PT_Locale>
</mdb:defaultLocale>
</xsl:copy>
</xsl:template>
<!-- replace cit:title -->
<xsl:template match="mdb:metadataIdentifier/mcc:MD_Identifier/mcc:authority/cit:CI_Citation/cit:title/gco:CharacterString/text()">
<xsl:value-of select="'UUID Test'"/>
</xsl:template>
<!-- add mcc:description -->
<xsl:template match="mdb:metadataIdentifier/mcc:MD_Identifier">
<xsl:apply-templates/>
<mcc:description>
<gco:CharacterString>Data was submitted
</gco:CharacterString>
</mcc:description>
</xsl:template>
<!-- update attribute 'codeLIst' value of mdb:metadataScope > mdb:MD_MetadataScope > mdb:resourceScope > mcc:MD_ScopeCode -->
<xsl:template match="mdb:metadataScope/mdb:MD_MetadataScope/mdb:resourceScope/mcc:MD_ScopeCode">
<xsl:if test="#codeListValue">
<xsl:attribute name="codeList">
<xsl:value-of select="'https://schemas.isotc211.org/19115/resources/Codelist/cat/codelists.xml#MD_ScopeCode'" />
</xsl:attribute>
</xsl:if>
</xsl:template>
<xsl:template name="add-iso19115-3.2018-namespaces">
<xsl:namespace name="xsi" select="'http://www.w3.org/2001/XMLSchema-instance'"/>
<xsl:namespace name="cit" select="'http://standards.iso.org/iso/19115/-3/cit/2.0'"/>
<xsl:namespace name="lan" select="'http://standards.iso.org/iso/19115/-3/lan/1.0'"/>
<xsl:namespace name="mcc" select="'http://standards.iso.org/iso/19115/-3/mcc/1.0'"/>
<xsl:namespace name="gco" select="'http://standards.iso.org/iso/19115/-3/gco/1.0'"/>
<xsl:namespace name="xlink" select="'http://www.w3.org/1999/xlink'"/>
</xsl:template>
</xsl:stylesheet>
The stylesheet above only work if the namespaces associated with mdb and cit in the original file are as below:
<mdb:MD_Metadata xmlns:mdb="http://standards.iso.org/iso/19115/-3/mdb/2.0"
xmlns:cit="http://standards.iso.org/iso/19115/-3/cit/2.0"
xmlns:lan="http://standards.iso.org/iso/19115/-3/lan/1.0"
xmlns:mcc="http://standards.iso.org/iso/19115/-3/mcc/1.0"
xmlns:gco="http://standards.iso.org/iso/19115/-3/gco/1.0">
....
How can I first update the namespaces and then apply the rest templates against the updated xml?
Perhaps the following is what you want, performing the namespace transformations and the other changes in one transformation step:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:cit1="http://standards.iso.org/iso/19115/-3/cit/1.0"
xmlns:cit="http://standards.iso.org/iso/19115/-3/cit/2.0"
xmlns:lan="http://standards.iso.org/iso/19115/-3/lan/1.0"
xmlns:mcc="http://standards.iso.org/iso/19115/-3/mcc/1.0"
xmlns:mco="http://standards.iso.org/iso/19115/-3/mco/1.0"
xmlns:mda="http://standards.iso.org/iso/19115/-3/mda/1.0"
xmlns:mdb1="http://standards.iso.org/iso/19115/-3/mdb/1.0"
xmlns:mdb="http://standards.iso.org/iso/19115/-3/mdb/2.0"
xmlns:gco="http://standards.iso.org/iso/19115/-3/gco/1.0"
xmlns:gcx="http://standards.iso.org/iso/19115/-3/gcx/1.0"
xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
exclude-result-prefixes="#all">
<xsl:output method="xml" indent="yes"/>
<!--Identity template that will copy every attribute, element, comment, and processing instruction to the output-->
<xsl:template match="#*|node()">
<xsl:copy copy-namespaces="no">
<!-- Including any attributes it has and any child nodes -->
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/mdb1:*">
<xsl:element name="mdb:{local-name()}">
<xsl:call-template name="add-iso19115-3.2018-namespaces"/>
<xsl:apply-templates select="#* , node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="mdb1:*">
<xsl:element name="mdb:{local-name()}">
<xsl:apply-templates select="#* , node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="cit1:*">
<xsl:element name="cit:{local-name()}">
<xsl:apply-templates select="#* , node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="mdb1:MD_Metadata">
<xsl:copy>
<xsl:apply-templates select="#* , node()"/>
<!-- add mdb:defaultLocale after mdb:metadataIdentifier -->
<mdb:defaultLocale>
<lan:PT_Locale id="EN">
<lan:language>
<lan:LanguageCode codeList="http://www.loc.gov/standards/iso639-2/" codeListValue="eng"/>
</lan:language>
<lan:characterEncoding>
<lan:MD_CharacterSetCode codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#MD_CharacterSetCode" codeListValue="utf8"/>
</lan:characterEncoding>
</lan:PT_Locale>
</mdb:defaultLocale>
</xsl:copy>
</xsl:template>
<!-- replace cit:title -->
<xsl:template match="mdb1:metadataIdentifier/mcc:MD_Identifier/mcc:authority/cit1:CI_Citation/cit1:title/gco:CharacterString/text()">
<xsl:value-of select="'UUID Test'"/>
</xsl:template>
<!-- add mcc:description -->
<xsl:template match="mdb1:metadataIdentifier/mcc:MD_Identifier">
<xsl:apply-templates/>
<mcc:description>
<gco:CharacterString>Data was submitted
</gco:CharacterString>
</mcc:description>
</xsl:template>
<!-- update attribute 'codeLIst' value of mdb:metadataScope > mdb:MD_MetadataScope > mdb:resourceScope > mcc:MD_ScopeCode -->
<xsl:template match="mdb1:metadataScope/mdb1:MD_MetadataScope/mdb1:resourceScope/mcc:MD_ScopeCode">
<xsl:if test="#codeListValue">
<xsl:attribute name="codeList">
<xsl:value-of select="'https://schemas.isotc211.org/19115/resources/Codelist/cat/codelists.xml#MD_ScopeCode'" />
</xsl:attribute>
</xsl:if>
</xsl:template>
<xsl:template name="add-iso19115-3.2018-namespaces">
<xsl:namespace name="xsi" select="'http://www.w3.org/2001/XMLSchema-instance'"/>
<xsl:namespace name="cit" select="'http://standards.iso.org/iso/19115/-3/cit/2.0'"/>
<xsl:namespace name="lan" select="'http://standards.iso.org/iso/19115/-3/lan/1.0'"/>
<xsl:namespace name="mcc" select="'http://standards.iso.org/iso/19115/-3/mcc/1.0'"/>
<xsl:namespace name="gco" select="'http://standards.iso.org/iso/19115/-3/gco/1.0'"/>
<xsl:namespace name="xlink" select="'http://www.w3.org/1999/xlink'"/>
</xsl:template>
</xsl:stylesheet>
I have a XML file where elements B are inside elements A and I want to move them up. From:
<?xml version="1.0" encoding="utf-8"?>
<root>
<A>
<C>Text</C>
Text again
More text
<D>Other text</D>
<B>Text again</B>
<C>No</C>
<D>May be</D>
<B>What?</B>
</A>
<A>
Something
<B>Nothing</B>
<D>Again</D>
<B>Content</B>
End
</A>
</root>
I would like to have:
<?xml version="1.0" encoding="utf-8"?>
<root>
<A>
<C>Text</C>
Text again
More text
<D>Other text</D>
</A>
<B>Text again</B>
<A>
<C>No</C>
<D>May be</D>
</A>
<B>What?</B>
<A>
Something
</A>
<B>Nothing</B>
<A>
<D>Again</D>
</A>
<B>Content</B>
<A>
End
</A>
</root>
The closest XSLT program I have is this:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="A">
<xsl:for-each select="*">
<xsl:choose>
<xsl:when test="name()='B'">
<xsl:apply-templates select="."/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="A">
<xsl:apply-templates select="."/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
It has two problems: it ignores text nodes (this is probably just a matter of adding |text() to the select="*") but, more important, it creates a element for each node while I would like them to stay together under one . For instance, the above stylesheet makes:
<A><C>No</C></A>
<A><D>May be</D></A>
where I want:
<A><C>No</C>
<D>May be</D></A>
In my XML files, are always direct children of , and there is no or nesting.
The main use case is producing HTML where UL and OL cannot be inside a P.
This question is related but not identical to xslt flattening out child elements in a DocBook para element (and may be also to Flatten xml hierarchy using XSLT
)
As I said in the comment to your question, this is not about moving elements up in hierarchy. It is about grouping nodes, and creating a new parent A element for each group determined by the dividing B element.
In XSLT 1.0 this can be achieved using a so-called sibling recursion:
XSLT 1.0
<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:template match="/root">
<xsl:copy>
<xsl:apply-templates select="A"/>
</xsl:copy>
</xsl:template>
<xsl:template match="A">
<xsl:copy>
<xsl:apply-templates select="node()[1][not(self::B)]" mode="sibling"/>
</xsl:copy>
<xsl:apply-templates select="B[1]" mode="sibling"/>
</xsl:template>
<xsl:template match="node()" mode="sibling">
<xsl:copy-of select="." />
<xsl:apply-templates select="following-sibling::node()[1][not(self::B)]" mode="sibling"/>
</xsl:template>
<xsl:template match="B" mode="sibling">
<xsl:copy-of select="." />
<xsl:if test="following-sibling::node()[normalize-space()]">
<A>
<xsl:apply-templates select="following-sibling::node()[1][not(self::B)]" mode="sibling"/>
</A>
<xsl:apply-templates select="following-sibling::B[1]" mode="sibling"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
An XSLT-1.0 solution - which is quite ugly - is the following. The output is as desired, but only for this simple MCVE. A general solution would be far more complicated as #michael.hor257k mentioned in the comments. Without more data it is unlikely to create a better solution in XSLT-1.0. Solutions for XSLT-2.0 and above may simplify this.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/root">
<xsl:copy>
<xsl:for-each select="A">
<xsl:if test="normalize-space(text()[1])">
<A>
<xsl:copy-of select="text()[1]" />
</A>
</xsl:if>
<xsl:if test="preceding::*">
<xsl:copy-of select="B[1]" />
</xsl:if>
<A>
<xsl:copy-of select="C[1] | C[1]/following-sibling::text()[1] | D[1]" />
</A>
<xsl:if test="not(preceding::*)">
<xsl:copy-of select="B[1]" />
</xsl:if>
<A>
<xsl:copy-of select="C[2] | C[2]/following-sibling::text()[1]" />
<xsl:if test="D[2]">
<xsl:copy-of select="D[2]" />
</xsl:if>
</A>
<xsl:copy-of select="B[2]" />
<xsl:if test="normalize-space(text()[last()])">
<A>
<xsl:copy-of select="text()[last()]" />
</A>
</xsl:if>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Concerning the situation of
<A><C>No</C></A>
<A><D>May be</D></A>
It is handled appropriately in the above code. So its output is
<A>
<C>No</C>
<D>May be</D>
</A>
Easy in XSLT 2 or 3 with group-adjacent=". instance of element(B)" or group-adjacent="boolean(self::B)", here is an XSLT 3 example (XSLT 3 is supported by Saxon 9.8 or 9.9 on Java and .NET (https://sourceforge.net/projects/saxon/files/Saxon-HE/) and by Altova since 2017 releases):
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="A">
<xsl:for-each-group select="node()" group-adjacent=". instance of element(B)">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:apply-templates select="current-group()"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy select="..">
<xsl:apply-templates select="current-group()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/gWmuiKv
In XSLT 2 you need to spell out the <xsl:mode on-no-match="shallow-copy"/> as the identity transformation template and use xsl:element instead xsl:copy:
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="A">
<xsl:for-each-group select="node()" group-adjacent=". instance of element(B)">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:apply-templates select="current-group()"/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="{name(..)}" namespace="{namespace-uri(..)}">
<xsl:apply-templates select="current-group()"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>
</xsl:transform>
http://xsltransform.hikmatu.com/pPqsHT2
If I decide to add a navpoint element in toc.ncx at the beginning of an existing toc.ncx in navmap, there is no way to reorder playOrder number but by hand. That could be really tedious if there are many navpoint elements.
Input
<?xml version="1.0" encoding="UTF-8"?>
<ncx version="2005-1" xmlns="http://www.daisy.org/z3986/2005/ncx/">
<head>
<meta name="dtb:uid" content="9781315348674" />
<meta name="dtb:depth" content="1" />
<meta name="dtb:totalPageCount" content="144" />
<meta name="dtb:maxPageNumber" content="144" />
</head>
<docTitle>
<text>Making Choices for Health Care</text>
</docTitle>
<navMap>
<navPoint id="nav-1">
<navLabel>
<text>Cover</text>
</navLabel>
<content src="xhtml/A01_cover.xhtml"/>
</navPoint>
<navPoint id="nav-2">
<navLabel>
<text>Half Title</text>
</navLabel>
<content src="xhtml/A02_halftitle.xhtml"/>
</navPoint>
</navMap>
</ncx>
Assuming Output Like:
<navPoint id="nav-1" playOrder="1">
<navLabel>
<text>1</text>
</navLabel>
<content src="Text/Section0002.xhtml"/>
</navPoint>
<navPoint id="nav-2" playOrder="2">
<navLabel>
<text>2</text>
</navLabel>
<content src="Text/Section0003.xhtml"/>
</navPoint>
XSLT code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<!-- Recursive copy template -->
<xsl:template match="node() | #*">
<xsl:copy>
<xsl:apply-templates select="node() | #*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="navPoint">
<xsl:copy>
<xsl:attribute name="playOrder">1</xsl:attribute>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<xsl:template match="#playOrder">
<xsl:attribute name="playOrder"><xsl:number count="*[#playOrder]" level="any"/></xsl:attribute>
</xsl:template>
</xsl:stylesheet>
This code is not working and can you please tell me the correct code
Use this:
<xsl:attribute name="playOrder"><xsl:number count="navPoint" level="any"/>/xsl:attribute>
instead of
<xsl:attribute name="playOrder">1</xsl:attribute>
and remove template
<xsl:template match="#playOrder">
<xsl:attribute name="playOrder"><xsl:number count="*[#playOrder]" level="any"/></xsl:attribute>
</xsl:template>
See transformation at https://xsltfiddle.liberty-development.net/94hvTyV/2
Assuming you just want normal 1,2,3 numbering, you could count() preceding nodes.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- Recursive copy template -->
<xsl:template match="node() | #*">
<xsl:copy>
<xsl:apply-templates select="node() | #*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="navPoint">
<xsl:copy>
<xsl:attribute name="playOrder">
<xsl:value-of select="count(preceding-sibling::navPoint) + 1" />
</xsl:attribute>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Given the following source xml:
<?xml version="1.0" encoding="UTF-8"?>
<Test xmlns="http://someorg.org">
<text>
<status value="generated"/>
<div xmlns="http://www.w3.org/1999/xhtml">
<p>Some text</p>
<p>Some text</p>
</div>
</text>
</Test>
I would like to have the same output as the above source xml (the source xml contains many other xml nodes but for this section, I want to output it as it is, with no changes.) I have the following xslt (see below) which strips the elements of their namespaces as desired. Unfortunately, it also strips the div elements of their name spaces but I want to retain them. The closest I got to achieving my aim is the following xslt but it outputs the div element twice because of the apply-templates but I only want the div element once with its namespace.
This is my xslt:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://someorg.org"
xmlns="http://someorg.org"
exclude-result-prefixes="f xsl">
<xsl:template match="*">
<xsl:element name="{local-name(.)}">
<xsl:apply-templates select="#* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:attribute name="{local-name(.)}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match = "f:text/f:status">
<status value ="generated"/>
<div xmlns="http://www.w3.org/1999/xhtml">
<xsl:apply-templates/>
</div>
</xsl:template>
</xsl:stylesheet>
Instead of trying to remove namespaces for all elements (as handled by your <xsl:template match="*"> template, you can only target elements in the "http://someorg.org" namespace. Simply change the template match to this
<xsl:template match="f:*">
For the elements in the "http://www.w3.org/1999/xhtml" namespace, you could use the identity template to pick up everything else
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:f="http://someorg.org">
<xsl:output method="xml" indent="yes" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="f:*">
<xsl:element name="{local-name(.)}">
<xsl:apply-templates select="#* | node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
add a template
<xsl:template match="*[local-name()='div'
and namespace-uri() = 'http://www.w3.org/1999/xhtml']">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
to perform a copy instead of creating a namespace-stripped element.
I'm trying to restructure some HTML using XSLT. How can I transform this:
<div>
<h2 class="foo">...</h2>
<p>bar</p>
</div>
into:
<div class="foo">
<h2>...</h2>
<p>bar</p>
</div>
In case you're using XSLT 1.0, the following XSLT
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="div">
<xsl:copy>
<xsl:attribute name="class">
<xsl:value-of select="h2/#class"/>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="h2/#class"/>
</xsl:stylesheet>
when applied to your input has the output
<div class="foo">
<h2>...</h2>
<p>bar</p>
</div>
The first template <xsl:template match="#*|node()">is an identity transformation - matching all attributes and other nodes, copying them and applying the identiy transformation to all child nodes and attributes of the current context node.
The empty template <xsl:template match="h2/#class"/> removes the class attribute from the h2, while the template matching the div copies the div and adds the class attribute of the h2 using
<xsl:attribute name="class">
<xsl:value-of select="h2/#class"/>
</xsl:attribute>
If you're using XSLT 2.0, this could be adjusted to
<xsl:attribute name="class" select="h2/#class"/>