Oracle XMLQuery 插入不需要的命名空间

Oracle XMLQuery inserting unwanted namespace

甲骨文 11.2

下面是 XMLQuery 我正在 运行 宁在 XMLType 专栏的精简版。当我 运行 查询时,它只是解析并重新创建存储的 XML 不需要的 默认和 tsip 名称空间被插入到父元素的子元素中。请注意,不会插入 tsxm 命名空间,这是因为它不等于默认命名空间此查询不执行任何操作并且可以轻松重写,但实际(更大)查询使用相同的方法,所以这就是我的原因以这种格式发布问题。

创建 table:

CREATE TABLE XML_DOCUMENT_TMP
(
  DOCUMENT_ID   NUMBER(12)                      NOT NULL,
  XML_DATA      SYS.XMLTYPE                     NOT NULL,
  CREATED_DATE  TIMESTAMP(6)                    NOT NULL
);

插入一些数据(必须具有原样的命名空间):

insert into XML_DOCUMENT_TMP
(document_id,created_date,xml_data)
values(1,sysdate, 
'<patent  xmlns="http://schemas.thomson.com/ts/20041221/tsip" 
    xmlns:tsip="http://schemas.thomson.com/ts/20041221/tsip" 
    xmlns:tsxm="http://schemas.thomson.com/ts/20041221/tsxm"  
    tsip:action="replace" tsip:cc="CA" tsip:se="2715340" tsip:ki="C">
    <accessions tsip:action="replace">
        <accession tsip:src="wila" tsip:type="key">CA-2715340-C</accession>
        <accession tsip:src="tscm" tsip:type="tscmKey">CA-2715340-C-20150804</accession>
    </accessions>
    <claimed tsip:action="replace">
    <    claimsTsxm tsip:lang="en">
            <tsxm:heading tsxm:align="left">We Claim:</tsxm:heading>
            <claimTsxm tsip:no="1" tsxm:num="1" tsip:type="main">1.  power.       </claimTsxm>
      </claimsTsxm>
  </claimed>
</patent>
');

运行 XMLQuery:

请注意对命名空间通配符的需求进行了解释

WITH tmpTable AS (
SELECT * FROM XML_DOCUMENT_TMP cm )
SELECT tt.xml_data ,
XMLQuery('declare default element namespace  "http://schemas.thomson.com/ts/20041221/tsip";
  declare namespace  tsip="http://schemas.thomson.com/ts/20041221/tsip";
  declare namespace  tsxm="http://schemas.thomson.com/ts/20041221/tsxm"; 


  return          
  <patent>{$m/*:patent/@*}
  {
    for $i in $m/*:patent/*
        return    $i
  }
  </patent>' 
        PASSING tt.xml_data as "m"   RETURNING CONTENT) newXml 
 FROM tmpTable tt
 WHERE tt.document_id in (1);

Returns:

<patent xmlns="http://schemas.thomson.com/ts/20041221/tsip" xmlns:tsip="http://schemas.thomson.com/ts/20041221/tsip" tsip:action="replace" tsip:cc="CA" tsip:se="2715340" tsip:ki="C">
    <accessions xmlns="http://schemas.thomson.com/ts/20041221/tsip" xmlns:tsip="http://schemas.thomson.com/ts/20041221/tsip" tsip:action="replace">
        <accession tsip:src="wila" tsip:type="key">CA-2715340-C</accession>
        <accession tsip:src="tscm" tsip:type="tscmKey">CA-2715340-C-20150804</accession>
    </accessions>
    <claimed xmlns="http://schemas.thomson.com/ts/20041221/tsip" xmlns:tsip="http://schemas.thomson.com/ts/20041221/tsip" tsip:action="replace">
        <claimsTsxm tsip:lang="en">
            <tsxm:heading xmlns:tsxm="http://schemas.thomson.com/ts/20041221/tsip" tsxm:align="left">We Claim:</tsxm:heading>
            <claimTsxm tsip:no="1" xmlns:tsxm="http://schemas.thomson.com/ts/20041221/tsip" tsxm:num="1" tsip:type="main">1.  power.</claimTsxm>
        </claimsTsxm>
</claimed>

如何删除在加入和声明的元素中创建的不需要的名称空间。 任何建议表示赞赏。

如果您尝试使用命名空间的各种值,您会发现虽然顶级 <patent> 级别的命名空间由于您所做的声明而被声明和包含,但在子元素级别此信息是没有按照您期望的方式使用。

XQuery 正在根据在该执行循环中考虑的节点中使用的名称空间提取名称空间,独立于整个文档。这就是每次 XQuery 循环时它们得到 "re-declared" 的原因。

其他文章解释说,您尝试做的是 "Parse" 数据以及 "Extract" 数据,这在一定程度上是正确的,因此 XSLT 是正确的工具,而不是比 XQuery。

我发现一个外部 link 有一个 XQuery 方法来剥离名称空间,因此返回给你 "raw" XML 是 here.

将该代码应用到您的 XQuery 使我:

SELECT xmlquery('xquery version "1.0"; (: :)
             declare default element namespace 
                        "http://www.somewherein.uk/ns/1.0"; (: :)

             declare function local:strip-namespace($inputRequest  as element()) as element()
             {
                element {xs:QName(local-name($inputRequest ))}
                {
                  for $child in $inputRequest /(@*,node())
                    return
                      if ($child instance of element())
                      then local:strip-namespace($child)
                      else $child
                }
             }; (: :)

             <patent>
             {
             for $s in /*:patent/*
              return local:strip-namespace($s)
             }
             </patent>' 
             PASSING cmf.XML_DATA 
             RETURNING content)
FROM XML_DOCUMENT_TMP cmf WHERE cmf.DOCUMENT_ID=1

一些进一步的编辑让我看到了下面的内容,我想这就是你想要的(在 patent 级别定义的命名空间)

SELECT xmlquery('xquery version "1.0"; (: :)
             declare default element namespace 
                        "http://www.somewherein.uk/ns/1.0"; (: :)

             declare function local:strip-namespace($inputRequest as element()) as element()
             {
                element {fn:name($inputRequest)}
                {
                  for $child in $inputRequest /(@*,node())
                    return
                      if ($child instance of element())
                      then local:strip-namespace($child)
                      else $child
                }
             }; (: :)

             <patent>
             {
             for $s in /(*:patent, node())
              return local:strip-namespace($s)
             }
             </patent>' 
             PASSING cmf.XML_DATA 
             RETURNING content)
FROM XML_DOCUMENT_TMP cmf WHERE cmf.DOCUMENT_ID=1;

如下所述,由于 XPath 中的一些问题,导致循环代码中出现一些重复。这也意味着 txsm 名称空间被声明了几次; XQuery 声明它 "the first time" 它在遍历该树分支时遇到正在使用它的命名空间,这意味着如果有兄弟姐妹使用 ns,那么它将被声明多次。通过将声明的显式位置移回父节点,我们可以消除它。

SELECT xmlquery('xquery version "1.0"; (: :)
             declare default element namespace  "http://schemas.thomson.com/ts/20041221/tsip"; (: :)
             declare namespace  tsip="http://schemas.thomson.com/ts/20041221/tsip"; (: :)
             declare namespace  tsxm="http://schemas.thomson.com/ts/20041221/tsxm"; (: :)

             declare function local:strip-namespace($inputRequest as element()) as element()
             {
                element {fn:name($inputRequest)}
                {
                  for $child in $inputRequest /(@*,node())
                    return
                      if ($child instance of element())
                      then local:strip-namespace($child)
                      else $child
                }
             }; (: :)

             <patent xmlns:tsxm="http://schemas.thomson.com/ts/20041221/tsxm" xmlns:tsip="http://schemas.thomson.com/ts/20041221/tsip">
             {
             for $s in /*:patent/*
              return local:strip-namespace($s)
             }
             </patent>' 
             PASSING cmf.XML_DATA
             RETURNING content)
FROM XML_DOCUMENT_TMP cmf WHERE cmf.DOCUMENT_ID=1;

稍微修改@Graham Nicol 的第二个解决方案,这似乎给出了正确答案:

SELECT xmlquery('xquery version "1.0";
         declare default element namespace 
                    "http://schemas.thomson.com/ts/20041221/tsip";

         declare function local:strip-namespace($inputRequest as element()) as element()
         {
            element {fn:name($inputRequest)}
            {
              for $child in $inputRequest /(@*,node())
                return
                  if ($child instance of element())
                  then local:strip-namespace($child)
                  else $child
            }
         }; 


         <patent>{/*:patent/@*}
         {
         for $s in /*:patent/*
          return local:strip-namespace($s)
        }
         </patent>
         ' 
         PASSING cmf.XML_DATA 
         RETURNING content)
FROM XML_DOCUMENT_TMP cmf WHERE cmf.DOCUMENT_ID=1;