2017-04-21 171 views
0

我想解析一個XML文本。它存儲在表t_testxml中的CLOB類型的列xml_data中。在Oracle中的XML解析

的XML是什麼樣子:

<?xml version="1.0" encoding="UTF-8"?> 
<defaultmpftest:defaultmpftest xmlns:defaultmpftest="http://test.com" 
test_id = "1231" 
test_name = "name_test"> 
</mpftestdata:additionalLinkUrl xmlns:mpftestdata="http://test2.com"/> 
</defaultmpftest:defaultmpftest> 

我怎樣才能提取爲test_id和TEST_NAME值是多少?

我想:

Select extract(xmltype.createxml(t.xml_data),'//defaultmpftest:defaultmpftest/@test_id').getStringVal() from t_testxml t; 

但不工作。我收到以下錯誤:

ORA-31011: XML Parsing failed 
LPX-00601: Invalid token in defaultmpftest:defaultmpftest/@test_id 

您能否就此問題給我一些建議?

謝謝!

+0

正如答案中指出的那樣,您發佈的原始XML無效,但如果按照所示方式運行,則在它有機會擊中LPX-00601之前,會得到一個不同的錯誤 - LPX-00231。在內部節點名稱開始處刪除雜亂的'/'會使XML有效,然後會給出你顯示的錯誤。顯示您實際使用的內容很有幫助。 [查看如何創建一個MCVE](https://stackoverflow.com/help/mcve)。 –

回答

3

在問題中顯示的XML是無效的,並會導致「LPX-00231:無效字符」如果你要的XMLType通過了它的錯誤。所以這不是你實際使用的字符串。在發佈問題時,我假設發生了一個錯誤,並且實際上得到了聲明的「LPX-00601:無效令牌」錯誤。所以我會以這個假設爲基礎,並以沒有錯字的字符串爲基礎。

extract is deprecated;但即便如此,在這裏使用它(與修正後的原始XML),你需要使用可選的第三個參數指定的命名空間:

select extract(xmltype.createxml(t.xml_data), 
    '//defaultmpftest:defaultmpftest/@test_id', 
    'xmlns:defaultmpftest="http://test.com"').getStringVal() 
from t_testxml t; 

EXTRACT(XMLTYPE.CREATEXML(T.XML_DATA),'//DEFAULTMPFTEST:DEFAULTMPFTEST/@TEST_ID','XMLNS:DEFAULTMPFTEST="HTTP://TEST.COM"').GETSTRINGVAL() 
----------------------------------------------------------------------------------------------------------------------------------------- 
1231 

而不是使用過時的功能,你可以使用XMLQuery

select xmlquery(
    'declare namespace defaultmpftest="http://test.com"; (: :) 
    //defaultmpftest:defaultmpftest/@test_id' 
    passing xmltype.createxml(t.xml_data) 
    returning content).getStringVal() 
from t_testxml t; 

XMLQUERY('DECLARENAMESPACEDEFAULTMPFTEST="HTTP://TEST.COM";(::)//DEFAULTMPFTEST:DEFAULTMPFTEST/@TEST_ID'PASSINGXMLTYPE.CREATEXML(T.XML_DATA)RETURNINGCONTENT).GETSTRINGVAL() 
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
1231 

您將需要兩個XMLQuery子句來獲取這兩個值。我通常會使用XMLTable代替,這裏示出與(固定的)經由一個CTE提供XML-AS-字符串:

with t_testxml(xml_data) as (select '<?xml version="1.0" encoding="UTF-8"?> 
<defaultmpftest:defaultmpftest xmlns:defaultmpftest="http://test.com" 
test_id="1231" 
test_name="name_test"> 
<mpftestdata:additionalLinkUrl xmlns:mpftestdata="http://test2.com"/> 
</defaultmpftest:defaultmpftest>' from dual 
) 
select x.test_id, x.test_name 
from t_testxml t 
cross join xmltable(
    xmlnamespaces('http://test.com' as "defaultmpftest"), 
    '//defaultmpftest:defaultmpftest' 
    passing xmltype(t.xml_data) 
    columns test_id number path '@test_id', 
    test_name varchar2(30) path '@test_name' 
) x; 

    TEST_ID TEST_NAME      
---------- ------------------------------ 
     1231 name_test      

Read more about using these functions

+0

謝謝!很有用!它有幫助。 – codi05ro

1

沒有很好地形成的XML,嘗試

<mpftestdata:additionalLinkUrl xmlns:mpftestdata="http://test2.com" />

<mpftestdata:additionalLinkUrl xmlns:mpftestdata="http://test2.com"></mpftestdata>

+0

謝謝您的回答,但我無法更改XML。我需要來自上層節點的信息。defaultmpftest:defaultmpftest – codi05ro

+0

提供的數據**不是XML **。因此你不能使用任何XML函數。在這種情況下,您必須使用REGEXP函數。 –

1

由於Wernfried Domscheit正確地指出:沒有很好地形成你的XML。對於非格式良好的XML,無法以常規方式提取信息。簡單地說,因爲常規的方法是用於XML而你的「XML」實際上不是一個XML。

讓我們嘗試非正規的方式,然後......

with t_testxml as (
    select q'{<?xml version="1.0" encoding="UTF-8"?> 
<defaultmpftest:defaultmpftest xmlns:defaultmpftest="http://test.com" 
test_id = "1231" 
test_name = "name_test"> 
</mpftestdata:additionalLinkUrl xmlns:mpftestdata="http://test2.com"/> 
</defaultmpftest:defaultmpftest>}' as xml_data 
    from dual 
) 
select xmlcast(xmlparse(content regexp_substr(T.xml_data, '<defaultmpftest:defaultmpftest[^>]+')||' />').extract('*/@test_id') as integer) as test_id 
from t_testxml T 
;