How to do multiple loops through XML in PL/SQL - sql

My XML looks like this
<data>
<row>
<id>1</id>
<name>John</name>
<name>Jack</name>
</row>
<row>
<id>2</id>
<name>Scott</name>
<name>Chuck</name>
<name>Kim</name>
</row>
</data>
I would like output:
->1
-->John
-->Jack
->2
-->Scott
-->Chuck
-->Kim
My current code looks like this:
DECLARE
X XMLTYPE := XMLTYPE('<?xml version="1.0" ?>
<data>
<row>
<id>1</id>
<name>John</name>
<name>Jack</name>
</row>
<row>
<id>2</id>
<name>Scott</name>
<name>Chuck</name>
<name>Kim</name>
</row>
</data>');
BEGIN
FOR R IN (SELECT EXTRACTVALUE(VALUE(P), '/row/id/text()') AS NAME
FROM TABLE(XMLSEQUENCE(EXTRACT(X, '//data/row'))) P)
LOOP
DBMS_OUTPUT.PUT_LINE('-->' || R.NAME);
END LOOP;
END;
I would need one more loop inside a row to loop through name tag, but I don't know how to do it.
A little help would be appreciated.

I figured it by myself:
DECLARE
X XMLTYPE := XMLTYPE('<?xml version="1.0" ?>
<data>
<row>
<id>1</id>
<promet>
<name>John</name>
<name>Jack</name>
</promet>
</row>
<row>
<id>2</id>
<promet>
<name>Scott</name>
<name>Chuck</name>
<name>Kim</name>
</promet>
</row>
</data>');
BEGIN
FOR R IN (SELECT EXTRACTVALUE(VALUE(P), '/row/id/text()') AS ID,
EXTRACT(VALUE(P), '/row/promet') AS PROMET
FROM TABLE(XMLSEQUENCE(EXTRACT(X, '//data/row'))) P)
LOOP
DBMS_OUTPUT.PUT_LINE('-->' || R.ID);
FOR R1 IN (SELECT EXTRACTVALUE(VALUE(T1), '/name/text()') AS NAME
FROM TABLE(XMLSEQUENCE(EXTRACT(R.PROMET, 'promet/name'))) T1)
LOOP
DBMS_OUTPUT.PUT_LINE('-->' || R1.NAME);
END LOOP;
END LOOP;
END;

Related

Query XDocument with LINQ to Return List

I have an xml String as so (shortened to only 2 Rows for ease of Testing ):
<?xml version="1.0" encoding="utf-8"?>
<DataTable Uid="DT_RetRes">
<Rows>
<Row>
<Cells>
<Cell>
<ColumnUid>AVAIL</ColumnUid>
<Value>N</Value>
</Cell>
<Cell>
<ColumnUid>ItemCode</ColumnUid>
<Value>PRODUCTID123#</Value>
</Cell>
<Cell>
<ColumnUid>Dscription</ColumnUid>
<Value>Basic Product 1 with hash</Value>
</Cell>
<Cell>
<ColumnUid>U_JOW_CMNT</ColumnUid>
<Value></Value>
</Cell>
</Cells>
</Row>
<Row>
<Cells>
<Cell>
<ColumnUid>AVAIL</ColumnUid>
<Value>Y</Value>
</Cell>
<Cell>
<ColumnUid>ItemCode</ColumnUid>
<Value>PRODUCTID234</Value>
</Cell>
<Cell>
<ColumnUid>Dscription</ColumnUid>
<Value>Basic Product 2 no hash</Value>
</Cell>
<Cell>
<ColumnUid>U_JOW_CMNT</ColumnUid>
<Value></Value>
</Cell>
</Cells>
</Row>
</Rows>
</DataTable>
I am trying to query the Xdocument to return a list of all ItemCode Values where the Value of
AVAIl is Y
My code Currently is as follows:
Dim xdoc As XDocument = XDocument.Parse(xmlString)
Dim result = xdoc.Elements("Rows").
Where(Function(x) x.Elements("ColumnUid").Value = "AVAIL" And
x.Elements("Value").Value = "Y").
Select(Function(x) x.<ItemCode>.Value).ToList
MessageBox.Show(result.Count)
However this never seems to return anything, I have Tried many variations of the Where and Select parts of the Query without Success. I am new to LINQ and can guess the query is constructed incorrectly, possibly not accessing the correct Element in the right way.
Any Help would be greatly appreciated.
I came up with this:
Dim isAvail = xDoc.<DataTable>.<Rows>.<Row>.<Cells>.
Where(Function(x) x.<Cell>.<ColumnUid>.Value = "AVAIL" AndAlso
x.<Cell>.<Value>.Value = "Y")
Dim availItemCodes = isAvail.<Cell>.
Where(Function(y) y.<ColumnUid>.Value = "ItemCode").<Value>.
Select(Function(v) v.Value)
isAvail is the list (well, IEnumerable) of <Cells> which have the desired <Cell> in them.
You can see how breaking it down into smaller statements makes it easier to work with.
An all in one approach, a more complex query admittedly,
First the XML
Dim someXML As XElement
'to load from file
' someXML=XElement.Load("path here")
'OR parse string
' someXML = XElement.Parse("string here")
'OR for testing use a literal
someXML = <DataTable Uid="DT_RetRes">
<Rows>
<Row>
<Cells>
<Cell>
<ColumnUid>AVAIL</ColumnUid>
<Value>N</Value>
</Cell>
<Cell>
<ColumnUid>ItemCode</ColumnUid>
<Value>PRODUCTID123#</Value>
</Cell>
<Cell>
<ColumnUid>Dscription</ColumnUid>
<Value>Basic Product 1 with hash</Value>
</Cell>
<Cell>
<ColumnUid>U_JOW_CMNT</ColumnUid>
<Value></Value>
</Cell>
</Cells>
</Row>
<Row>
<Cells>
<Cell>
<ColumnUid>AVAIL</ColumnUid>
<Value>Y</Value>
</Cell>
<Cell>
<ColumnUid>ItemCode</ColumnUid>
<Value>PRODUCTID234</Value>
</Cell>
<Cell>
<ColumnUid>Dscription</ColumnUid>
<Value>Basic Product 2 no hash</Value>
</Cell>
<Cell>
<ColumnUid>U_JOW_CMNT</ColumnUid>
<Value></Value>
</Cell>
</Cells>
</Row>
</Rows>
</DataTable>
Then the code
Dim ie As IEnumerable(Of String)
ie = From el In someXML.<Rows>.<Row>.<Cells>.<Cell>
Where el.<ColumnUid>.Value = "AVAIL" AndAlso el.<Value>.Value = "Y"
From item In el.Parent.<Cell>
Where item.<ColumnUid>.Value = "ItemCode"
Select item.<Value>.Value

How to extract a nested array value frm XML in DataWeave and convert to CSV

I am getting this value from the database
<row>
<file_data>One</file_data>
<time_inserted>2019-01-30T10:29:20.543</time_inserted>
</row>
<row>
<file_data>two</file_data>
<time_inserted>2019-01-30T10:29:20.547</time_inserted>
</row>
<row>
<file_data>three</file_data>
<time_inserted>2019-01-30T10:29:20.550</time_inserted>
</row>
<row>
<file_data>four</file_data>
<time_inserted>2019-01-30T10:29:20.550</time_inserted>
</row>
<row>
<file_data>five</file_data>
<time_inserted>2019-01-30T10:29:20.553</time_inserted>
</row>
And I would like to output it as a CSV like this
one
two
three
four
five
I managed to solved my problem thusly:
Firstly I added a step in my logic to surround the data with a "rows" element so that it ended up looking like this:
<rows>
<row>
<file_data>One</file_data>
<time_inserted>2019-01-30T12:34:00.277</time_inserted>
</row>
<row>
<file_data>two</file_data>
<time_inserted>2019-01-30T12:34:00.277</time_inserted>
</row>
<row>
<file_data>three</file_data>
<time_inserted>2019-01-30T12:34:00.280</time_inserted>
</row>
<row>
<file_data>four</file_data>
<time_inserted>2019-01-30T12:34:00.280</time_inserted>
</row>
<row>
<file_data>five</file_data>
<time_inserted>2019-01-30T12:34:00.283</time_inserted>
</row>
</rows>
I then wrote this code to get the list output that I needed:
def responses = new XmlSlurper().parseText(xmlData)
def payload = ""
responses.row.findAll { p ->
p.file_data
}
.each { p ->
payload = payload + "${p.file_data}" + "\r\n"
}
print payload
And this outputs:
one
two
three
four
five
Hope below logic is works. please check it.
%dw 2.0
output application/java
---
payload.rows.*row map ($.file_data) reduce (($$ ++ "\n" ++ $))

How to concate joined table fields for xml

Hi have data structure like this :
CREATE TEMP TABLE test_names (
id serial primary key,
name character varying(50),
age int
);
INSERT INTO test_names(name,age) values ('name1',10),('name2',20);
CREATE TEMP TABLE test_names_details (
id serial primary key,
test_names_id int,
col1 int,
col2 int,
col3 int
);
INSERT INTO test_names_details(test_names_id,col1,col2,col3)
VALUES(1,2,3,4),(1,5,6,7),(1,8,9,10),(2,20,21,22),(2,23,24,25)
Want from this tables select data like xml :
<info>
<maininfo>
<pn name="name">name1</pn>
<age name="age">10</age>
</maininfo>
<data>
<row>
<col1 name="col1">2</col1>
<col2 name="col2">3</col1>
<col3 name="col3">4</col1>
</row>
<row>
<col1 name="col1">5</col1>
<col2 name="col2">6</col1>
<col3 name="col3">7</col1>
</row>
<row>
<col1 name="col1">8</col1>
<col2 name="col2">9</col1>
<col3 name="col3">10</col1>
</row>
</data>
<maininfo>
<pn name="name">name2</pn>
<age name="age">20</age>
</maininfo>
<data>
<row>
<col1 name="col1">20</col1>
<col2 name="col2">21</col1>
<col3 name="col3">22</col1>
</row>
<row>
<col1 name="col1">23</col1>
<col2 name="col2">24</col1>
<col3 name="col3">25</col1>
</row>
</data>
</info>
How to do it ?
Wrap this in a function and off you go! ;-)
SELECT
'<info>' ||
string_agg(
'<maininfo>' ||
'<pn name="name">' || name || '</pn>' ||
'<age name="age">' || age || '</age>' ||
'</maininfo>' ||
'<data>' ||
(SELECT
string_agg(
'<row>' ||
'<col name="col1">'||col1||'</col>' ||
'<col name="col2">'||col2||'</col>' ||
'<col name="col3">'||col3||'</col>' ||
'</row>', '')
FROM test_names_details WHERE test_names_id = test_names.id
) ||
'</data>'
, '') ||
'</info>'
FROM test_names

how to delete empty namespace from child element in sql server

I am trying to delete empty namespace from the child element. I tried with following code but its not deleting
SET #xDocTemp.modify('declare default element namespace "mynamepsace";
delete /worksh/Data/row[#xmlns=""]')
xml data:
<worksh xmlns="mynamespace">
<Data>
<row r="1" ht="18">
<row xmlns="" rl="39" spans="2">
<row xmlns="" rl="39" spans="2">
</Data>
<worksh>
Expected output
<worksh xmlns="mynamespace">
<Data>
<row rl="1" ht="18">
<row rl="39" spans="2">
<row rl="39" spans="2">
</Data>
<worksh>
not sure if it's possible with modify(), but you can just replace it like
set #xDocTemp = select cast(replace(cast(#xDocTemp as nvarchar(max)), ' xmlns=""', '') as xml)

Extracting xmlsequence from another xmlsequance in SQL

I have small problem with xmlsequence. I am codding in PL-SQL (Oracle)
Let's say, my XML looks like this:
<Row name="Row1">
<Field name="Filed1">
<Value1>
</Value1>
</Field>
<Row name="Row2inRow1">
<Field name="Filed2">
<Value1>
</Value1>
</Field>
</Row>
<Row name="Row2inRow1">
<Field name="Filed2">
<Value1>
</Value1>
</Field>
</Row>
<Row name="Row1">
<Field name="Filed1">
<Value1>
</Value1>
</Field>
<Row name="Row2inRow1">
<Field name="Filed2">
<Value1>
</Value1>
</Field>
</Row>
<Row name="Row2inRow1">
<Field name="Filed2">
<Value1>
</Value1>
</Field>
</Row>
It has 2x same "Row1" which is multiplicated, what's more inside Row1 I have multiplicated "Row2inRow1".
The problem is, I would like to select values from Ro2InRow1 and from Row1, to concat them, the effect should be:
Value1 (from 1st Row1) || Value1 (from 1st Row2inRow1)
Value1(from 1st Row1) || Value1 (from 2nd Row2InRow1)
Value1 (from 2nd Row1) || Value1 (from 3rd Row2inRow1)
Value1(from 2nd Row1) || Value1 (from 4th Row2InRow1)
I've tried to code is somehow, but I can't force my query to work right:
declare
xml_data xmldata;
begin
for rec1 in(select extractvalue(value(x),'//Field[#name="Filed1"]/Value1') ValueOfField1,
from table(xmlsequence(extract(xml_data.data,'//Row[#name="Row1"]')))x )
loop
dbms_output.put_line('1 : '|| ValueOfField1);
for rec2 in(select extractvalue(value(x),'//Field[#name="Filed2"]/Value1') ValueOfField2,
from table(xmlsequence(extract(xml_data.data,'//Row[#name="Row2inRow1"]')))k ) --? What here!
loop
dbms_output.put_line('1 : '|| ValueOfField2);
end loop;
end loop;
end;
Any ideas ? :(