0

I'm trying to transform an input XML to a new XML format altogether.It isn't preserving the namespaces on the Output XML. I have tried few suggestions from SO, but since I am creating new root elements it is not preserving the namespaces. Any help is much appreciated! Thanks in Advance!

The input XML is :

<Container
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://hgkl.kj.com">
 <Request>
  <Id>Guid</Id>
  <Name>ABC</Name>
 </Request>
</Container>

The XSLT :

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


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

 <xsl:template match="/*"> 
   <xsl:variable name="root" select="name()" />
   <xsl:element name="{$root}">
      <xsl:apply-templates select="child::*"/>
   </xsl:element>
 </xsl:template>

<xsl:template match="child::*"> 
  <xsl:element name="Input">
    // rest of the logic
  </xsl:element>
</xsl:template>

</xsl:stylesheet>

The expected output :

<?xml version="1.0" encoding="UTF-8"?>
<Container>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://hgkl.kj.com">
 <Input>
    // rest of the logic for forming the element
  </Input>
</Container>

The root tag and other tags in the XML are dynamic. The main objective behind the transformation is to convert the incoming XML elements and attributes to another language [like : Spanish] based on the value in the dictionary xml. Similar to the post

Mukund Kn
  • 45
  • 5

2 Answers2

1

If your input XML has default namespace, the relevant XSL stylesheet must define the namespace-prefix and use it @match attribute of xsl:template as long as you use XSLT 1.0. So the following XSLT stylesheet will satisfy your requirements:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ins="http://hgkl.kj.com"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    >

    <xsl:output  indent="yes"/>

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

    <xsl:template match="/ins:*"> 
        <xsl:variable name="root" select="local-name()"/>
        <xsl:element name="{$root}" namespace="http://hgkl.kj.com">
            <xsl:for-each select="namespace::node()">
                <xsl:copy/>
            </xsl:for-each>
            <xsl:apply-templates select="child::*"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="ins:*"> 
        <xsl:element name="Input" namespace="http://hgkl.kj.com">
            // rest of the logic
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

[The result]

<?xml version="1.0" encoding="utf-8"?>
<Container xmlns="http://hgkl.kj.com" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <Input>
    // rest of the logic
   </Input>
</Container>
Toshihiko Makita
  • 1,294
  • 1
  • 8
  • 15
  • Thanks for helping out. But, the default namespaces are not present in the output even after defining them in the XSL. Like [link](http://www.utilities-online.info/xsltransformation/?save=b7309ac9-88b2-4c2c-9bc7-b671bc7fa7bd-xsltransformation#.We2IIGiCyUk) – Mukund Kn Oct 23 '17 at 06:14
  • Your link does not contain @namespace attribute on xsl:element. – Toshihiko Makita Oct 23 '17 at 06:43
  • In my example i have only included xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" namespaces. Do I have to write a template match for /xsi:* ? This namspace thing is a bit confusing for me though – Mukund Kn Oct 23 '17 at 07:25
  • 1
    Yes, as long as you need to use xsl:element instruction, @namespace attribute is indispensable for generating elements that belongs (default) namespace. Otherwise the generated element belongs no-namespace. – Toshihiko Makita Oct 23 '17 at 10:54
1

First, on the question as asked.

Your input has a text node reading

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://hgkl.kj.com">

as a child of the input. It's not being propagated to the output because your template for the outermost element (with match="/*") applies templates only to child elements. If you change

  <xsl:apply-templates select="child::*"/> 

in that template to

  <xsl:apply-templates/>

the output is as you show it.

Second, on the question as you may perhaps have intended it.

If we assume that the > at the end of the first line in your sample input and output is a mistake, so that the input and output documents are supposed to have namespace declarations binding prefixes xsd and xsi and the default namespace, then the output you are getting does not have the namespace declarations because you are specify that the output contains an element with the QName given by $root, which in this case has the value Container.

If you want an output element in with the same expanded name, replace

<xsl:element name="{$root}">
  ...
</

with

<xsl:copy>
  ...
</
C. M. Sperberg-McQueen
  • 24,596
  • 5
  • 38
  • 65