【问题标题】:How to select a particular Node name and its values in XML using Oracle SQL query?如何使用 Oracle SQL 查询在 XML 中选择特定节点名称及其值?
【发布时间】:2015-01-29 12:25:51
【问题描述】:

我有一个名为 SOAP_MONITORING 的表,其中有 RESPONSE_XML 列,它是 CLOB 数据类型。在此列中存储大型 xml 字符串。我想从此 xml 字符串中获取节点名称和节点值。这是我的 xml:

<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><ns:placeShopOrderResponse xmlns:ns="http://service.soap.CDRator.com">
<ns:return xmlns:ax2133="http://signup.data.soap.CDRator.com/xsd" xmlns:ax2134="http://core.signup.data.soap.CDRator.com/xsd" xmlns:ax2127="http://data.soap.CDRator.com/xsd" xmlns:ax2129="http://webshop.data.soap.CDRator.com/xsd" xmlns:ax2130="http://core.data.soap.CDRator.com/xsd" xmlns:ax2140="http://core.result.service.soap.CDRator.com/xsd" xmlns:ax2139="http://result.service.soap.CDRator.com/xsd" xmlns:ax2147="http://webshop.result.service.soap.CDRator.com/xsd" xmlns:ax2148="http://mandate.result.service.soap.CDRator.com/xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ax2147:PlaceShopOrderResultDTO">
<ax2130:id xsi:nil="true" /><ax2140:description>SOAP_GLOBAL_SUCCESS</ax2140:description>
<ax2147:subscriptions xsi:type="ax2127:SubscriptionDTO"><ax2130:id>201501070917439804</ax2130:id>
<ax2130:id>201501070917439804</ax2130:id>
</ns:return></ns:placeShopOrderResponse>
</soapenv:Body>
</soapenv:Envelope>

我想查询此列以获得SUBSCRIPTION_ID,即201501070917439804。我试过上面的查询

SELECT extractvalue(RESPONSE_XML, '/*/ax2130/*/id/@value')
FROM SOAP_MONITORING where WEB_SERVICE_NAME='RatorWebShopService' and WEB_METHOD_NAME='placeShopOrder'

但收到错误

ORA-00932: inconsistent datatypes: expected - got -
00932. 00000 -  "inconsistent datatypes: expected %s got %s"

为了运行这样的查询以从 xml 中获取节点值,我非常陌生。

【问题讨论】:

  • 快速回答是使用XMLType(RESPONSE_XML),但这似乎不是有效的XML:LPX-00225: end-element tag "ns:return" does not match start-element tag "ax2147:subscriptions"。好像少了一个结束标签? (另外,extractvalue() is deprecated)。
  • 实际上它是一个巨大的 xml,我已经从中删除了一些部分。这样我就可以在这里展示它。你能告诉我使用 XMLType 的查询吗?当我的列数据类型是 CLOB 时它会起作用吗?
  • 我觉得你应该看看here
  • 我试过这种方式 SELECT XMLTYPE(RESPONSE_XML).extract('//ax2130:id/text()').getStringVal() FROM SOAP_MONITORING where WEB_SERVICE_NAME='RatorWebShopService' and WEB_METHOD_NAME=' placeShopOrder' 但是它给出了一个错误,因为 XML 配对失败,无效的令牌 '//ax2130:id/text()'。
  • 当你这样做SELECT XMLTYPE(RESPONSE_XML) FROM SOAP_MONITORING where WEB_SERVICE_NAME='RatorWebShopService' and WEB_METHOD_NAME='placeShopOrder'时,你会得到一个错误吗?

标签: sql oracle xml-parsing nsxmlelement extract-value


【解决方案1】:

您可以将您的 CLOB 转换为 XMLType,假设它是有效的,只需:

extractvalue(XMLType(RESPONSE_XML), ...

如果您在其中存储 XML,不确定为什么您的列类型不是 XMLType,但这并不完全相关。

然后您可以将命名空间提供给extractvalue()

SELECT extractvalue(XMLType(RESPONSE_XML),
  '//ax2130:id/text()',
  'xmlns:ax2130="http://core.data.soap.CDRator.com/xsd"')
FROM SOAP_MONITORING
where WEB_SERVICE_NAME='RatorWebShopService' and WEB_METHOD_NAME='placeShopOrder';

.. 但你有多个 ID,所以你得到:ORA-19025: EXTRACTVALUE returns value of only one node

extractvalue 已弃用,as noted in the documentation

您可以改用XQuery,特别是这里的XMLTable。

假设您只希望 ax2130:id 值嵌套在 ax2147:subscription 中,您可以使用这个 XQuery:

SELECT xt.id
FROM SOAP_MONITORING sm
CROSS JOIN XMLTable(XMLNAMESPACES (
      'http://schemas.xmlsoap.org/soap/envelope/' AS "soapenv",
      'http://service.soap.CDRator.com' as "ns",
      'http://core.data.soap.CDRator.com/xsd' as "ax2130",
      'http://webshop.result.service.soap.CDRator.com/xsd' as "ax2147"
    ),
    'for $i in /soapenv:Envelope/soapenv:Body/ns:placeShopOrderResponse/ns:return/ax2147:subscriptions
      return $i/ax2130:id'
    passing XMLType(sm.RESPONSE_XML)
    columns "ID" number path '/') xt
where WEB_SERVICE_NAME='RatorWebShopService' and WEB_METHOD_NAME='placeShopOrder';

                   ID
---------------------
   201501070917439804 
   201501070917439804 

 2 rows selected 

或者,如果您想要任何ax:2130 节点,包括空白节点,您可以使用:

SELECT xt.id
FROM SOAP_MONITORING sm
CROSS JOIN XMLTable(XMLNAMESPACES (
      'http://core.data.soap.CDRator.com/xsd' as "ax2130"
    ),
    'for $i in //ax2130:id return $i'
    passing XMLType(sm.RESPONSE_XML)
    columns "ID" number path '/') xt
where WEB_SERVICE_NAME='RatorWebShopService' and WEB_METHOD_NAME='placeShopOrder';

                   ID
---------------------

   201501070917439804 
   201501070917439804 

 3 rows selected 

只有 XQuery 中引用的名称空间需要在 XMLNamespaces 子句中指定。

如果需要,您可以根据所选 ID 加入另一个表:

SELECT xt.id
FROM SOAP_MONITORING sm
CROSS JOIN XMLTable(XMLNAMESPACES (
    ...) xt
JOIN someothertable sot on sot.id = xt.id
where sm.WEB_SERVICE_NAME='RatorWebShopService'
and sm.WEB_METHOD_NAME='placeShopOrder';

【讨论】:

  • 非常感谢。经过长时间的尝试,它可以工作。只是一个小查询。现在我得到了所有的 SUBSCRIPTION_ID。我想把这个 SUBSCRIPTION_ID 和另一个表连接起来。那么在这种情况下,我可以为这个完整的 sql 查询创建别名并简单地使用这个 SUBSCRIPTION_ID 来加入其他表吗?
  • 您可以添加一个连接到另一个表,并使用xt.id作为连接条件;我已将其更改为 ANSI 格式的交叉连接(而不是在表之间使用逗号)以使其更清晰并使其他连接更好地工作。
  • 请检查我更新的问题。我只有一个 xml 列,我尝试了与查询相同的方式来获取新的 orderType。但出现错误。
  • 好的,亚历克斯很抱歉,因为我改变了问题。
【解决方案2】:

做:

"SELECT extractvalue(XMLTYPE(RESPONSE_XML), '/*/ax2130/*/id/@value')
     FROM SOAP_MONITORING where WEB_SERVICE_NAME='RatorWebShopService' and WEB_METHOD_NAME='placeShopOrder'"

代替:

SELECT extractvalue(RESPONSE_XML, '/*/ax2130/*/id/@value')
    FROM SOAP_MONITORING where WEB_SERVICE_NAME='RatorWebShopService' and WEB_METHOD_NAME='placeShopOrder'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多