1

I think the best way to ask this question is: How do I specify a default namespace for the root element in the output? Doing this:

<xsl:template match="/">
        <r xmlns:s"http://www.mycompany.com/s/schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.mycompany.com/default/schema" >
....
....

Gives me an error in Oracle:

ORA-31011: XML Parsing Failed
ORA-19201: Error occurred in in XML Processing
LPX-00604: Invalid attribute 'nIfNotExist', for attribute 'name'
ORA-06512: at SYS.XMLType at line 74 
ORA-06512: at line 24

where the 'nIfNotExist' is a template:

 <xsl:template name="nIfNotExist" xmlns:scom="http://www.mycomapny.com/s/schema">
  <xsl:param name="nodeToTest"/>
  <xsl:param name="nodeName"/>
                ...

I want the resulting document to have the root element look like this:

<r xmlns:s="http://www.mycompany.com/s/schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.mycompany.com/default/schema">

I want "http://www.mycompany.com/default/schema" as the default namespace so the document can pass XSD validation. Otherwise, I have to add it manually before running validation (not an option for batch processing).

EDIT

I have tried this:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:s="http://www.mycompany.com/schema"
 xmlns="http://www.mycompany.com/def_schema">

The result is a document with no data, like this:

<r xmlns:s="http://www.mycompany.com/schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.mycompany.com/def_schema">
    <a></a>
    <s:b></s:b>
    <c></c>
    ....

It should have been:

<r xmlns:s="http://www.mycompany.com/schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.mycompany.com/def_schema">
    <a>123</a>
    <s:b>ABC34L</s:b>
    <c>7.092381</c>

UPDATE

Source data looks something like this (input that I get has no namespaces defined in it):

<ROOT_NODE>
    <DATA_A>1234</DATA_A>
    <DATA_B>34567</DATA_B>
    <OTHER_DATA_C>7.123456</OTHER_DATA_C>
</ROOT_NODE>

Desired output

<r xmlns:s="http://www.mycompany.com/schema"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   xmlns="http://www.mycompany.com/def_schema">
    <a>1234</a>
    <s:b>34567</s:b>
    <c>7.123456</c>
</r>
2
  • Please, provide the source XML document on which the transformation is applied. Also, please, provide the result you want to get from the transformation. Commented Sep 20, 2010 at 18:59
  • I posted my answer and it contains a reasonably short and straight-forward, complete solution. Commented Sep 20, 2010 at 20:17

3 Answers 3

1

This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:s="http://www.mycompany.com/schema"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://www.mycompany.com/def_schema"
 >
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

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

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

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

  <xsl:template match="DATA_B">
   <s:b>
    <xsl:apply-templates/>
   </s:b>
  </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<ROOT_NODE>
    <DATA_A>1234</DATA_A>
    <DATA_B>34567</DATA_B>
    <OTHER_DATA_C>7.123456</OTHER_DATA_C>
</ROOT_NODE>

produces the wanted result:

<r xmlns:s="http://www.mycompany.com/schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.mycompany.com/def_schema">
    <a>1234</a>
    <s:b>34567</s:b>
    <c>7.123456</c>
</r>
Sign up to request clarification or add additional context in comments.

8 Comments

Hmm, I tried this in Oracle (Exact input and XSLT as here) and all it produced was <r xmlns="http://www.mycompany.com/def_schema">1234345677.123456</r> (Oracle 10g) At least it got the default namespace right. Same technique didn't work on the main document, though the main document only has one template for root element then all other transforms under that.
It appears to be concatenating the contents of DATA_A, DATA_B, and OTHER_DATA_C, and making that the content of r.
@FrustratedWithFormsDesigner: Then either you dont have the same XML as the one you provided, or ORacle's XSLT processor that you are using has some bug.
@Dimitre: The results I described are based on your transformation in this post and the copy of the sample input I described.
@Alejandro: It probably is. I haven't confirmed an actual bug in Oracle (10.2), though it seems that's what I'm facing. To make things more fun, it looks like Oracle's XSLT processor follows XSLT 1.0 and some small parts of 2.0. So, I think at this point I need an Oracle-specific workaround for what should have been pretty easy to solve.
|
1

You're halfway to the right answer. When you declare a default namespace at the root of the transform, you are asserting (assuming that you don't override the declaration elsewhere) that all of the non-qualified elements in that document belong to that namespace. Every non-qualified element that the transform emits will belong to that namespace. You've got that part right.

What I think you're probably overlooking is that namespace declarations in an XSLT transform also apply to the XPath patterns in the transform. I'd bet that the XPath node tests in your transform aren't matching any of the input nodes because the input nodes are in the empty namespace, not the namespace you've declared in the transform.

What you probably want to do is something like this:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:s="http://www.mycompany.com/schema" 
 xnlns:no=""
 xmlns="http://www.mycompany.com/def_schema">

...and then change the patterns in the transform accordingly:

<xsl:template match="no:foo">
   <foo>...</foo>
</xsl:template>

This is, by the way, one of the reasons that xsl:element exists - you can build a template that transforms elements from one namespace to another with it, e.g.:

<xsl:template match="no:*">
   <xsl:element name="{local-name()}">
      <xsl:apply-templates select="node()|@*"/>
   </xsl:element>
</xsl:element>

Edit:

I haven't played around with namespace in quite this way before, and it turns out that the above is not actually legal. You can't specify no namespace with a namespace prefix. So you can't use the target namespace as the default namespace of your transform, because then you have no way of telling XPath to find the elements in the source document.

You can either specify the output namespace with a prefix, e.g.:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:s="http://www.mycompany.com/schema" 
 xmlns:out="http://www.mycompany.com/def_schema">

...but that will write the out namespace prefix to the output, which won't bother any XML processor but might bother humans. Or you can specify it explicitly in your templates, e.g.:

<xsl:template match="foo">
   <xsl:element name="foo" namespace="http://www.mycompany.com/def_schema">
      ...
   </xsl:element>
</xsl:template>

4 Comments

The trick with xmlns:no="" causes Oracle to say "LPX-00284: namespace prefix to NULL URI is not allowed". Also, PL/SQL Developer doesn't allow it either, saying that only a default namespace can be null (I had cheat - I had to load it from a text editor rather than the XML editor).
Your second suggestion, might work... I got a default namespace appearing on the root node in the output! The only problem is... I still need the declarations of the other namespaces (my s namespace and the xsi namespace). It looks like Oracle doesn't support the xsl:namespace element... Assuming Oracle only (safely) supports XSLT 1.0, how can I have multiple namespaces declared on an element?
If your transform emits any nodes in those two namespaces, XSLT will add the namespace declarations. If not, it won't. But you shouldn't need those namespace declarations if there aren't any nodes in those namespaces.
Also: Oracle's not to blame for that LPX-00284 error, I am. XML doesn't allow you to associate a namespace prefix with no namespace, and I should have tested that before blithely telling you it would work.
0

There are many possible solutions, but none seem to work well in Oracle, from PL/SQL. One of the other devs here "solved" this by converting the XML object to a CLOB, performing some string manipulation to force the default namespace into the root element, and then converting back to XML for the next step... I don't like it but it works...

Comments

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.