2017-04-21 170 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 
;