2016-07-29 17 views
10

Oracle 11,2Oracle XMLQUERY chèn namespace không mong muốn

Dưới đây là một phiên bản cắt giảm của một XMLQuery tôi đang chạy trên một cột XMLType. Khi tôi chạy truy vấn, chỉ đơn giản là phân tích cú pháp và tạo lại các XML được lưu trữ, các không mong muốn các không gian tên mặc định và tsip được chèn vào các phần tử con của phụ huynh. Lưu ý rằng không gian tên tsxm không được chèn vào, điều này là bởi vì nó không bằng không gian tên mặc định Truy vấn này không có gì và có thể viết lại dễ dàng, nhưng truy vấn thực (lớn hơn) sử dụng cùng phương pháp này vì vậy đây là lý do tại sao tôi đăng câu hỏi ở định dạng này.

tạo bảng:

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

Chèn một số dữ liệu (mà phải có không gian tên như là):

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

Chạy XMLQuery:

Lưu ý sự cần thiết của namespace wildcarding là được giải thích 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); 

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> 

Làm thế nào để thoát khỏi không gian tên mong muốn tạo ra trong gia nhập và khẳng định yếu tố. Bất kỳ đề xuất nào được đánh giá cao.

+0

Một cách nhanh chóng & bẩn sẽ được xử lý đầu ra của bạn với XSLT sử dụng bản sắc biến đổi. Có vẻ như quá mức cần thiết, tôi sẽ miễn cưỡng gọi đó là giải pháp tốt nhất của bạn trừ khi nó trở thành người duy nhất, nhưng tôi nghi ngờ điều đó. – Flynn1179

+0

@ Flynn1179 Giải pháp này (thực hiện xử lý xml trong XMLQuery) là chính xác để tránh sử dụng xslt, mà nó quá chậm (đối với các XMLTypes lớn). –

+0

Bạn có thể thử 'DBMS_XMLDOM.REMOVEATTRIBUTE' không? Tôi không chắc chắn nếu nó là một giải pháp làm việc. – Mark

Trả lời

2

Nếu bạn chơi xung quanh với các giá trị khác nhau của không gian tên, bạn có thể thấy rằng trong khi mức trên cùng là <patent> mức không gian tên được khai báo và bao gồm do khai báo bạn thực hiện, ở cấp độ phần tử con thông tin này không được sử dụng trong cách mà bạn đang mong đợi.

XQuery sẽ trích xuất các không gian tên dựa trên những vùng được sử dụng trong các nút đang được xem xét trong vòng lặp thực hiện đó, không phụ thuộc vào toàn bộ tài liệu. Đây là lý do tại sao họ nhận được "tái tuyên bố" mỗi khi XQuery đi vòng vòng.

Các bài viết khác giải thích rằng những gì bạn đang cố gắng làm là "Phân tích cú pháp" dữ liệu cũng như "Trích xuất" nó, điều này đúng với một mức độ và XSLT là công cụ phù hợp hơn là XQuery.

Một liên kết bên ngoài tôi đã tìm thấy có cách XQuery loại bỏ các không gian tên và do đó trả lại cho bạn XML "thô" là here.

Áp dụng mà mã để XQuery của bạn đã có tôi:

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 

Một số chỉnh sửa thêm đã cho tôi đến dưới đây, mà tôi nghĩ là những gì bạn đang theo đuổi (không gian tên được xác định ở cấp 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; 

Như đã nhận xét dưới đây dẫn đến một số trùng lặp trong mã vòng lặp, do một số vấn đề trong XPath. Nó cũng có nghĩa là không gian tên txsm được khai báo một vài lần; XQuery tuyên bố nó là "lần đầu tiên" nó gặp phải không gian tên đang được sử dụng khi nó đi vào nhánh cây đó có nghĩa là nếu có các anh chị em sử dụng ns thì nó sẽ được khai báo nhiều lần.Bằng cách di chuyển vị trí rõ ràng của khai báo trở lại nút cha, chúng ta có thể loại bỏ điều đó.

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

Tôi đã nhìn thấy liên kết đó nhưng tôi không thể nhận được "hàm khai báo" để hoạt động. Tôi nhận được: ORA-19193: XQST0045: Đó là lỗi tĩnh nếu tên hàm trong khai báo hàm nằm trong một trong các không gian tên sau đây: http://www.w3.org/XML/1998/namespace ... Nếu bạn có thể đăng một phiên bản sửa đổi làm việc của xQuery của tôi thì bạn có thể vui vẻ có các điểm. –

+0

Chưa hoàn hảo, nhưng bằng cách thêm không gian tên 'cục bộ' vào chức năng delcaration, tôi đã nhận được nó khi gọi hàm. Nó bây giờ có một loại không phù hợp (của '% s' chống lại'% s' bizarrely) –

+0

Đó là một nỗ lực khá. Tôi nhận thấy rằng bạn đã không tuyên bố $ inputRequest, như đề xuất trong liên kết của bạn (vì nó tạo ra lỗi ORA-19112) Tôi tự hỏi nếu đây là vấn đề? –

1

giải pháp thứ 2 sửa đổi @Graham Nicol của hơn một chút, điều này dường như để cung cấp cho câu trả lời đúng:

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

Có, điều đó dường như đến cùng một điểm. Sự khác biệt mà chúng tôi vẫn có là danh sách "tự động" so với "rõ ràng" của các không gian tên trong phần tử '' hàng đầu, gây ra thay đổi về cách không gian tên "phân phối". –

+0

@graham, chúng tôi không thể mã hóa cứng các khai báo ns trong vì chúng khác nhau, chúng phải đến từ xml. Chúng tôi chỉ có các khai báo ns trong phần tử gốc nên {/ *: patent/@ *} phải ổn. –

Các vấn đề liên quan