0

I have an input xml -

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Root xmlns="http://www.somenamespace">
    <Child1>
        <A>a</A>
        <B>b</B>
    </Child1>
    <Child2>
        <C>c</C>
        <D>d</D>
    </Child2>
</Root>

I want my output xml after transformation to remove the namespace from root and add it to Element Child1 instead like this-

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<NewRoot>
    <NewChild1 xmlns="http://www.somenamespace">
        <A>a</A>
        <B>b</B>
    </NewChild1>
    <NewChild2>
        <C>c</C>
        <D>d</D>
    </NewChild2>
</NewRoot>

My xslt looks like-

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            xmlns="http://www.somenamespace"
            xmlns:test="http://www.somenamespace"
            exclude-result-prefixes="test">
    <xsl:output method="xml" indent="yes" version="1.0" encoding="UTF-8" standalone="yes"/>
    <xsl:template match="/">
    <NewRoot>
        <xsl:apply-templates select="test:Root/test:Child1"/>
        <xsl:apply-templates select="test:Root/test:Child2"/>
    </NewRoot>
    </xsl:template>
    <xsl:template match="test:Root/test:Child1">
         <NewChild1> <xsl:value-of select="current()"/> </NewChild1>
    </xsl:template>
    <xsl:template match="test:Root/test:Child2">
         <NewChild2> <xsl:value-of select="current()"/> </NewChild2>
    </xsl:template>
</xsl:stylesheet>

Currently this adds the namespace to the NewRoot element.

3
  • 1
    Are you sure that's what you want? This will do much more than just "move the namespace": it will transfer the entire Child2 branch from its namespace to no-namespace. Commented Jul 6, 2016 at 1:20
  • 1
    The reason that NewRoot goes into namespace http://www.somenamespace is because of the xmlns="http://www.somenamespace" namespace declaration, which affects all literal result elements whose name is unprefixed. Commented Jul 6, 2016 at 7:50
  • michael.hor257k's comment above is apparently referring to what the OP's output example will do (by moving the default namespace declaration), not what the stylesheet will do. Commented Jul 6, 2016 at 16:09

2 Answers 2

1

You can change it as follows:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            xmlns:test="http://www.somenamespace"
            exclude-result-prefixes="test">
    <xsl:output method="xml" indent="yes" version="1.0" encoding="UTF-8" standalone="yes"/>
    <xsl:template match="/">
    <NewRoot>
        <xsl:apply-templates select="test:Root/test:Child1"/>
        <xsl:apply-templates select="test:Root/test:Child2"/>
    </NewRoot>
    </xsl:template>
    <xsl:template match="test:Root/test:Child1">
         <test:NewChild1> <xsl:value-of select="current()"/> </test:NewChild1>
    </xsl:template>
    <xsl:template match="test:Root/test:Child2">
         <NewChild2> <xsl:value-of select="current()"/> </NewChild2>
    </xsl:template>
</xsl:stylesheet>

I.e. don't declare a default namespace (xmlns="...") but put NewChild1 explicitly in the http://www.somenamespace namespace.

This does what you asked, namely, modifies your stylesheet to "remove the namespace from root and add it to Element Child1"; but it does not produce your example output in all details (e.g. the <A> and <B> elements are still not preserved, as you didn't ask for help with that). Rather than completely rewriting your stylesheet to reproduce aspects of the example output that may not be what you intended to focus on, I'll leave it at that and let you provide feedback as to what else you specifically needed help with.

In all this, it will save time and make communication easier if you make sure you understand the difference between namespace declarations, namespace prefixes, and what namespace an element is in.

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

7 Comments

This does not produce the expected result.
@michael.hor257k: I can believe that may be true, but it would be more helpful if you state what you think the expected result is (since the question is vague on that point) or how it differs from the result of the above.
The question has the exact expected result - at least that's what I took the second block of code for. It's only 10 lines, so I believe you should be able to spot the differences right away. If not, I suggest you use a diff tool.
@michael.hor257k: The question has a specific example of the expected result ("like this"), but it doesn't appear to be the actual data the OP wants to transform, and the question does not specify all aspects of what the transformation should do in principle. Like in what way? Also, the OP shows signs of common confusions about namespaces, which is an additional reason that it's unsafe to take the example as a full specification.
That being said, I admit I haven't tested my code. That's why I can believe your first comment was true. I'm going to test it as soon as I have time.
|
0

I'd suggest you do it this way:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns="http://www.somenamespace"
exclude-result-prefixes="ns">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="ns:Child1">
    <NewChild1 xmlns="http://www.somenamespace">
        <xsl:copy-of select="*"/>
    </NewChild1>
</xsl:template>

<xsl:template match="ns:Child2">
    <NewChild2>
        <xsl:apply-templates mode="no-namespace"/>
    </NewChild2>
</xsl:template>

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

</xsl:stylesheet>

4 Comments

This adds the namespace to Child1, but adds a xmlns="" to all child elements of Child1 i.e to A and B. I'd like A and B to also fall under the same namespace. How can I do that?
"adds a xmlns="" to all child elements of Child1 i.e to A and B." No, it doesn't: xsltransform.net/bFN1yaj
@eechpeech: Are you sure you're running michael.hor's stylesheet against your original XML? It should never put A and B in no namespace. What XSLT processor are you using? I tested it using Saxon and it didn't do what you described.
@LarsH I'm using Xalan 2.7.2. I also needed to have only one child in my output i.e only B and to do that, I removed xsl:copy-of select="*". When I did this, B was preceded by xmlns="". The above solution works fine for my initial question though

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.