简体   繁体   中英

How Extract from XMLTYPE column, corresponding label for value in a tag within a value/label list from same XML

I got a sql from an Oracle table with a XMLTYPE column. The Xml has a tag with a value '2' and in the same xml there is the list with value/label pairs like this:

<?xml version="1.0" encoding="UTF-8"?>
<Root>
    <characteristics>
        <motor>
            <fuel>2</fuel>
        </motor>
    </characteristics>
    <ValuesList>
        <CarValues>
            <CarValue>
                <value>1</value>
                <label>Diesel</label>
            </CarValue>
            <CarValue>
                <value>2</value>
                <label>Unleaded petrol</label>
            </CarValue>
        </CarValues>
    </ValuesList>
</Root>

With extract() or extractValue() functions it's easy to get the value for tag with any of these staments a, b

SELECT extract(t.xmlColumn, '//fuel/text()').getStringVal() a,
       extractValue(t.xmlColumn, '//fuel') b
  FROM Table t

The problem is I want to get the label text for value '2' from Valueslist 'Unleaded petrol'

I try to get that value with a XPATH expresion like this:

extractValue(t.xmlColumn, '//CarValue/label[../value=//fuel]')

The XPATH has been evaluated with Notepad XML Tools and it works, but there's no way to get any result. it's always null.

Any idea how to achive this? I don't know how to use XMLTABLE or any other solution to this case.

You need to include the /text() part in your attempt:

SELECT
extract(t.xmlColumn,'//fuel/text()').getStringVal() a
,extractValue(t.xmlColumn,'//fuel') b
,extractValue(t.xmlColumn, '//CarValue/label[../value=//fuel/text()]') c
FROM your_table t
A B C
2 2 Unleaded petrol

In your version you're trying to match a label with a value of the node <fuel>2</fuel> , not the text within than node, 2 .

Both extract() and extractValue() are deprecated, so you could use XMLQuery instead:

SELECT
XMLQuery('//fuel/text()' passing xmlColumn returning content) a
,XMLQuery('//CarValue/label[../value=//fuel/text()]/text()' passing xmlColumn returning content) a
FROM your_table t
A A
2 Unleaded petrol

Or with XMLTable();

SELECT x.a, x.b
FROM your_table t
CROSS APPLY XMLTable(
  '/'
  passing t.xmlColumn
  columns a number path '//fuel',
    b varchar2(30) path '//CarValue/label[../value=//fuel/text()]'
) x
A B
2 Unleaded petrol

fiddle


If your version of Oracle isn't working with the node traversal using ../ then you could do it the hard way by getting the fuel value and all the id/label pairs with separate XMLTable calls, and then filtering those that match:

SELECT x1.fuel, x2.label
FROM your_table t
CROSS JOIN XMLTable(
  '//fuel'
  passing t.xmlColumn
  columns fuel number path '.'
) x1
JOIN XMLTable(
  '//CarValue'
  passing t.xmlColumn
  columns value number path 'value',
    label varchar2(30) path 'label'
) x2 ON x2.value = x1.fuel
FUEL LABEL
2 Unleaded petrol

fiddle

All solutions Alex Poole gave are accepted solutions for the question case title where "a value/label list within same XML" is present.

Just for information, in case "a value/label list is not present in the same XML", solution is create an auxiliary XMLTable with a XMLTYPE field and the value/label list XML in it.

SELECT x1.fuel, x2.labelFROM your_table t
CROSS JOIN XMLTable(
  '//fuel'
  passing t.xmlColumn
  columns fuel number path '.'
) x1
LEFT JOIN XMLTable(
  '//CarValue'
  passing 
  (SELECT XMLTYPE('
    <ValuesList>
        <CarValues>
            <CarValue>
                <value>1</value>
                <label>Diesel</label>
            </CarValue>
            <CarValue>
                <value>2</value>
                <label>Unleaded petrol</label>
            </CarValue>
        </CarValues>
    </ValuesList>
  ') FROM dual)
  columns value number path 'value',
    label varchar2(30) path 'label'
) x2 ON x2.value = x1.fuel

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM