2016-07-29 24 views
10

甲骨文11.2甲骨文的XMLQuery將不需要命名空間

下面是一個XMLQuery我跑的上XMLType列削減版本。當我運行查詢時,它會簡單地解析並重新創建存儲的XML不需要的默認和tsip命名空間會插入到父級的子元素中。請注意,tsxm命名空間沒有被插入,這是因爲它不等於默認的命名空間。這個查詢什麼都不做,很容易被重寫,但真正的(更大的)查詢使用了相同的方法,所以這就是爲什麼我以這種格式發佈問題。

創建表:

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

注意需要命名空間通配符是解釋here

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

返回:

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

如何擺脫在種質創建不必要的命名空間和要求的元素。 任何建議表示讚賞。

+0

一個快速和骯髒的方法是使用恆等變換XSLT處理您的輸出。看起來雖然過分,但我不願意稱之爲你的最佳解決方案,除非它是唯一的解決方案,但我對此表示懷疑。 – Flynn1179

+0

@ Flynn1179此解決方案(在XMLQuery中執行xml處理)恰恰是爲了避免使用xslt,它太慢(對於大型XMLType)。 –

+0

你可以試試'DBMS_XMLDOM.REMOVEATTRIBUTE'嗎?我不確定它是否是一個可行的解決方案。 – Mark

回答

2

如果使用名稱空間的各種值,可以看到,頂級<patent>級別的名稱空間由於所做的聲明而被聲明和包含,因此在子元素級別,此信息不會用於你期待的方式。

XQuery正在基於那些在執行循環中考慮的節點中使用的名稱空間提取名稱空間,而與整個文檔無關。這就是爲什麼每次XQuery進行循環時都會重新聲明它們。

其他文章解釋說,你試圖做的是「解析」數據以及「提取」它,這在一定程度上是真實的,所以XSLT是合適的工具而不是XQuery。

我發現了一個外部鏈接,它具有剝離命名空間的XQuery方法,因此返回「原始」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聲明它「第一次」遇到正在使用它的名稱空間,因爲它走過那個樹分支,這意味着如果有同胞使用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; 
+0

我已經看到了這個鏈接,但是我無法使「聲明函數」正常工作。我得到: ORA-19193:XQST0045:如果函數聲明中的函數名稱位於以下命名空間之一中,則這是一個靜態錯誤:http://www.w3.org/XML/1998/namespace ... 如果您可以發佈我的xQuery的修訂版本,那麼您可以高興地獲得這些觀點。 –

+0

還不完美,但通過將'local'命名空間添加到函數調用中,我已經調用函數了。它現在有一個類型不匹配('%s'與奇怪的'%s') –

+0

這是一個體面的努力。我注意到你沒有聲明$ inputRequest,正如你的鏈接建議(因爲它會產生ORA-19112錯誤)我不知道這是否是問題? –

1

修憲@Graham尼科爾的第2個解決方案略有下降,這似乎給出正確的答案:

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; 
+0

是的,這似乎達到了同樣的觀點。我們仍然存在的一個區別是頂部「」元素中名稱空間的「自動」與「顯式」列表,這會導致名稱空間自身「分佈」的方式發生變化。 –

+0

@graham我們不能硬編碼中的ns聲明,因爲它們有所不同,它們必須來自xml。我們在根元素中只有ns聲明,所以 {/ *:patent/@ *}應該沒問題。 –