0

I'm writing a wrapper layer over an existing out of the box service. For this, I need to convert the namespaces of the xml that is returned by the service to my namespaces The xml has different namespaces for different tags, and I need to map them to another set of namespaces In other words, the prefix ns1 to be modified to myns1 ns2 to myns2, and so on...

Here is how my XML looks like

<ns1:Response>
   <ns2:task>..</ns2:task>
   <ns2:address>..</ns2:address>
   <ns2:pin>..</ns2:pin>
   <ns3:address>
      <ns4:add1>..</ns4:add1>
      <ns4:add2>..</ns4:add2>
      <ns4:add3>
        <ns5:asdf>..</ns5:asdf>
        <ns5:qwe>..</ns5:qwe>
      </ns4:add3>
      <ns4:add4>..</ns4:add4>
    </ns3:address>
    <ns2:query>..</ns2:query>
</ns1:Response>

And I want to change this to

<myns1:Response>
   <myns2:task>..</myns2:task>
   <myns2:address>..</myns2:address>
   <myns2:pin>..</myns2:pin>
   <myns3:address>
      <myns4:add1>..</myns4:add1>
      <myns4:add2>..</myns4:add2>
      <myns4:add3>
        <myns5:asdf>..</myns5:asdf>
        <myns5:qwe>..</myns5:qwe>
      </myns4:add3>
      <myns4:add4>..</myns4:add4>
    </myns3:address>
    <myns2:query>..</myns2:query>
</myns1:Response>

Basically, just the namespace prefixes change from one set to another. Can you please suggest me how to do this in xslt? I've tried using apply-templates, but i'm not able to figure out a solution

Regards Ravi

1

1 Answer 1

0

The following stylesheet worked!

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:myns1="http://www.w3.org/TR/html4/1"
xmlns:myns2="http://www.w3.org/TR/html4/2"
xmlns:myns3="http://www.w3.org/TR/html4/3"
xmlns:myns4="http://www.w3.org/TR/html4/4"
xmlns:myns5="http://www.w3schools.com/furniture"
xmlns:ns1="http://www.w3.org/TR/html4/1"
xmlns:ns2="http://www.w3.org/TR/html4/2"
xmlns:ns3="http://www.w3.org/TR/html4/3"
xmlns:ns4="http://www.w3.org/TR/html4/4"
xmlns:ns5="http://www.w3schools.com/furniture">

<xsl:template match="*">
  <myns1:taskListResponse>
    <xsl:apply-templates/>
  </myns1:taskListResponse>
</xsl:template>

<xsl:template match="ns2:*">
  <xsl:element name="myns2:{local-name()}">
    <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

<xsl:template match="ns3:*">
  <xsl:element name="myns3:{local-name()}">
    <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

<xsl:template match="ns4:*">
  <xsl:element name="myns4:{local-name()}">
    <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

<xsl:template match="ns5:*">
  <xsl:element name="myns5:{local-name()}">
    <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

</xsl:stylesheet>

But seriously, I'm not able to understand how this works.

The snippet

<xsl:template match="ns2:*">
  <xsl:element name="myns2:{local-name()}">
    <xsl:value-of select="." />
  </xsl:element>
</xsl:template>

means match all elements that start with ns2: and replace with myns2:

But when I used the same logic for all, it gave only the first 2 level elements

Ex : Stylesheet

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:myns1="http://www.w3.org/TR/html4/1"
xmlns:myns2="http://www.w3.org/TR/html4/2"
xmlns:myns3="http://www.w3.org/TR/html4/3"
xmlns:myns4="http://www.w3.org/TR/html4/4"
xmlns:myns5="http://www.w3schools.com/furniture"
xmlns:ns1="http://www.w3.org/TR/html4/1"
xmlns:ns2="http://www.w3.org/TR/html4/2"
xmlns:ns3="http://www.w3.org/TR/html4/3"
xmlns:ns4="http://www.w3.org/TR/html4/4"
xmlns:ns5="http://www.w3schools.com/furniture">

<xsl:template match="/">
  <myns1:taskListResponse>
    <xsl:apply-templates/>
  </myns1:taskListResponse>
</xsl:template>

<xsl:template match="ns2:*">
  <xsl:element name="myns2:{local-name()}">
    <xsl:value-of select="." />
  </xsl:element>
</xsl:template>

<xsl:template match="ns3:*">
  <xsl:element name="myns3:{local-name()}">
    <xsl:value-of select="." />
  </xsl:element>
</xsl:template>

<xsl:template match="ns4:*">
  <xsl:element name="myns4:{local-name()}">
    <xsl:value-of select="." />
  </xsl:element>
</xsl:template>

<xsl:template match="ns5:*">
  <xsl:element name="myns5:{local-name()}">
    <xsl:value-of select="." />
  </xsl:element>
</xsl:template>

</xsl:stylesheet>

returned

    <?xml version="1.0" encoding="UTF-8"?><myns1:taskListResponse xmlns:ns2="http://www.w3.org/TR/html4/2" xmlns:ns3="http://www.w3.org/TR/html4/3" xmlns:ns4="http://www.w3.org/TR/html4/4" xmlns:ns5="http://www.w3schools.com/furniture" xmlns:myns1="http://www.w3.org/TR/html4/1" xmlns:myns2="http://www.w3.org/TR/html4/2" xmlns:myns3="http://www.w3.org/TR/html4/3" xmlns:myns4="http://www.w3.org/TR/html4/4" xmlns:myns5="http://www.w3schools.com/furniture" xmlns:ns1="http://www.w3.org/TR/html4/1">
       <myns2:task>..</myns2:task>
       <myns2:address>..</myns2:address>
       <myns2:pin>..</myns2:pin>
       <myns3:address>
          ..
          ..

            ..
            ..

          ..
        </myns3:address>
        <myns2:query>..</myns2:query>
    </myns1:taskListResponse>

Here, you can see that ns4 & ns5 elements are completely missed. Where for the same template, instead of <xsl:value-of select="." />, If i use <xsl:apply-templates/>, it worked, meaning replaced all the level nodes. I seriously dont understand this as the match I used is * in the template.

Appreciate your response.

Regards Ravi

Sign up to request clarification or add additional context in comments.

3 Comments

Actually, you are processing ns2 only, because <xsl:value-of/> simply outputs a copy of the current node's contents; they are not run through any processing. <apply-templates/> on the other hand instructs XSLT to process the current node's contents with the rules available.
Hi Levente, Thanks for the response. What I understood from your comment is that <xsl:value-of/> works only on the current level node, so only the ns2: nodes are returned. If you observe the output, ns3 also got applied. But I also have the next template for ns4, ns5. Why are they skipped? Is it that when the xslt processor encountered <xsl:value-of/>, it processes that particular template and stopped going forward? And for <xsl:apply-templates/>, it continued to ns3 template, then ns4 and ns5? My question may seem a bit silly, but I want to understand the concept behind it. Thanks.
@user2350784 It is difficult for you to see what is happening, but due to the built-in rules, when you use xsl:apply-templates in the template for the root node, it is "pushing" the document element ns1:Response, which matches the built-in template rule and "push" the children of ns1:Response. The ns2:* and ns3:* templates match those elements. If those templates re-construct the matched element and use xsl:value-of it uses the computed text for that element and will not process any of it's children. When you use xsl:apply-templates, it "pushes" it's children to match templates.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.