Oracle XSLT:默认命名空间导致空标记

时间:2010-09-20 14:56:06

标签: xml oracle xslt xpath xml-namespaces

我认为提出这个问题的最好方法是:如何为输出中的根元素指定默认命名空间?这样做:

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

在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

其中'nIfNotExist'是模板:

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

我希望生成的文档的根元素如下所示:

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

我希望"http://www.mycompany.com/default/schema"作为默认命名空间,以便文档可以通过XSD验证。否则,我必须在运行验证之前手动添加它(不是批处理的选项)。

修改

我试过这个:

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

结果是没有数据的文档,如下所示:

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

应该是:

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

更新

源数据看起来像这样(我得到的输入中没有定义名称空间):

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

期望的输出

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

3 个答案:

答案 0 :(得分:1)

此转化

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

应用于提供的XML文档

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

产生想要的结果

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

答案 1 :(得分:0)

你已经到了正确答案的一半。当您在转换的根处声明默认命名空间时,您断言(假设您不在其他地方覆盖声明)该文档中的所有非限定元素都属于该命名空间。转换发出的每个非限定元素都属于该命名空间。你有那个部分。

我认为您可能忽略的是,XSLT转换中的命名空间声明也适用于转换中的XPath模式。我敢打赌,你的转换中的XPath节点测试不匹配任何输入节点,因为输入节点在空命名空间中,而不是你在转换中声明的命名空间。

你可能想要做的是这样的事情:

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

...然后相应地更改变换中的模式:

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

顺便说一句,这是xsl:element存在的原因之一 - 您可以构建一个模板,用以将元素从一个名称空间转换为另一个名称空间,例如:

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

修改

之前我没有以这种方式玩过命名空间,事实证明上述内容实际上并不合法。您不能使用名称空间前缀指定任何名称空间。所以你不能使用目标命名空间作为转换的默认命名空间,因为那时你无法告诉XPath在源文档中找到元素。

您可以使用前缀指定输出命名空间,例如:

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

...但是这会将 out 命名空间前缀写入输出,这不会打扰任何XML处理器,但可能会打扰人类。或者您可以在模板中明确指定它,例如:

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

答案 2 :(得分:0)

有许多可能的解决方案,但似乎没有一个在PL / SQL中在Oracle中运行良好。其中一个开发人员通过将XML对象转换为CLOB,执行一些字符串操作以将默认命名空间强制转换为根元素,然后转换回XML以进行下一步,从而“解决”了这一点...我不知道喜欢它,但它有效...