Oracle XSLT: default namespace results in empty tags

社会主义新天地 提交于 2019-12-02 03:39:30

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>

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>

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...

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!