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.
CodePudding user response:
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 |
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 |