Search code examples
xsltxslt-2.0

Insert element and add prefix using xslt


I need to add or insert another element and attribute <vat:IRmark Type="generic"/> after the <DefaultCurrency>. And, there is a certain group which is the <Group> element that I need to add a prefix. I almost did it, but the insertion of element didn't working. Here is my sample test file:

INPUT File:

<Data>
<Record>
    <ID>123-AAA</ID>
    <Date>2017-04-23</Date>
    <Group>
        <Hdr>
            <ID>833-AAA</ID>
            <DefaultCurrency>GBP</DefaultCurrency>
            <Sender>truth</Sender>
        </Hdr>
    </Group>
</Record>

GENERATED OUTPUT:

<Data>
<Record xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:vat="http://www.govtalk.gov.uk/taxation/vat/vatdeclaration/2" schemaLocation="http://www.govtalk.gov.uk/CM/envelope http://www.govtalk.gov.uk/taxation/vat/vatdeclaration/2">
    <ID>123-AAA</ID>
    <Date>2017-04-23</Date>
  <vat:Group>
     <vat:Hdr>
        <vat:ID>833-AAA</vat:ID>
        <vat:DefaultCurrency>GBP</vat:DefaultCurrency>
        <vat:Sender>truth</vat:Sender>
     </vat:Hdr>
  </vat:Group>
</Record>

EXPECTED OUTPUT:

    <Data>
<Record xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:vat="http://www.govtalk.gov.uk/taxation/vat/vatdeclaration/2" schemaLocation="http://www.govtalk.gov.uk/CM/envelope http://www.govtalk.gov.uk/taxation/vat/vatdeclaration/2">
    <ID>123-AAA</ID>
    <Date>2017-04-23</Date>
  <vat:Group>
     <vat:Hdr>
        <vat:ID>833-AAA</vat:ID>
        <vat:DefaultCurrency>GBP</vat:DefaultCurrency>
        <vat:IRmark Type="generic"/>
        <vat:Sender>truth</vat:Sender>
     </vat:Hdr>
  </vat:Group>
</Record>

XSLT Code:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:vat="http://www.govtalk.gov.uk/taxation/vat/vatdeclaration/2">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()[boolean(normalize-space())]|@*"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="DefaultCurrency">
    <xsl:copy-of select="."/>
        <vat:IRmark>
            <xsl:attribute name="Type">generic</xsl:attribute>
        </vat:IRmark>
</xsl:template>
<xsl:template match="*[ancestor-or-self::Group]">
    <xsl:element name="vat:{local-name()}">
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>
<xsl:template match="Record">
    <Record xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:vat="http://www.govtalk.gov.uk/taxation/vat/vatdeclaration/2" schemaLocation="http://www.govtalk.gov.uk/CM/envelope http://www.govtalk.gov.uk/taxation/vat/vatdeclaration/2">
        <xsl:apply-templates/>
    </Record>
</xsl:template>

Thank you.


Solution

  • This is because of template priority. The template that matches *[ancestor-or-self::Group] will match also the element DefaultCurrency. Because of the condition in the template match, the template has a higher priority (0.5, I think, compared with a priority of 0 for the template matching DefaultCurrency) and so this template will be used.

    To get around this, assign a manual priority to your template that matches DefaultCurrency

     <xsl:template match="DefaultCurrency" priority="1">
    

    You can read up on conflict resolution for templates at https://www.w3.org/TR/xslt#conflict