How to extract element-path from XMLType Node? - sql

I would like to have a select statement on an XML document and one column should return me the path of each node.
For example, given the data
SELECT *
FROM TABLE(XMLSequence(
XMLTYPE('<?xml version="1.0"?>
<users><user><name>user1</name></user>
<user><name>user2</name></user>
<group>
<user><name>user3</name></user>
</group>
<user><name>user4</name></user>
</users>').extract('/*//*[text()]'))) t;
Which results in
column_value
--------
<user><name>user1</name></user>
<user><name>user2</name></user>
<user><name>user3</name></user>
<user><name>user4</name></user>
I'd like to have a result like this:
path value
------------------------ --------------
/users/user/name user1
/users/user/name user2
/users/group/user/name user3
/users/user/name user4
I can not see how to get to this. I figure there are two thing that have to work together properly:
Can I extract the path from an XMLType with a single operation or method, or do I have to do this with string-magic?
What is the correct XPath expression so that I do get the whole element path (if thats possible), eg. <users><group><user><name>user3</name></user></group></user> insead of <user><name>user3</name></user>?
Maybe I am not understanding XMLType fully, yet. It could be I need a different approach, but I can not see it.
Sidenotes:
In the final version the XML document will be coming from CLOBs of a table, not a static document.
The path column can of course also use dots or whatever and the initial slash is not the issue, any representation would do.
Also I would not mind if every inner node also gets a result row (possibly with null as value), not only the ones with text() in it (which is what I am really interested in).
In the end I will need the tail element of path separate (always "name" in the example here, but this will vary later), i.e. ('/users/groups/user', 'name', 'user3'), I can deal with that separately.

You can achieve that with help of XMLTable function from Oracle XML DB XQuery function set:
select * from
XMLTable(
'
declare function local:path-to-node( $nodes as node()* ) as xs:string* {
$nodes/string-join(ancestor-or-self::*/name(.), ''/'')
};
for $i in $rdoc//name
return <ret><name_path>{local:path-to-node($i)}</name_path>{$i}</ret>
'
passing
XMLParse(content '
<users><user><name>user1</name></user>
<user><name>user2</name></user>
<group>
<user><name>user3</name></user>
</group>
<user><name>user4</name></user>
</users>'
)
as "rdoc"
columns
name_path varchar2(4000) path '//ret/name_path',
name_value varchar2(4000) path '//ret/name'
)
For me XQuery looks at least more intuitive for XML data manipulation than XSLT.
You can find useful set of XQuery functions here.
Update 1
I suppose that you need totally plain dataset with full data at last stage.
This target can be reached by complicated way, constructed step-by-step below, but this variant is very resource-angry. I propose to review final target (selecting some specific records, count number of elements etc.) and after that simplify this solution or totally change it.
Update 2
All steps deleted from this Update except last because #A.B.Cade proposed more elegant solution in comments.
This solution provided in Update 3 section below.
Step 1 - Constructing dataset of id's with corresponding query results
Step 2 - Aggregating to single XML row
Step 3 - Finally get full plain dataset by querying constracted XML with XMLTable
with xmlsource as (
-- only for purpose to write long string only once
select '
<users><user><name>user1</name></user>
<user><name>user2</name></user>
<group>
<user><name>user3</name></user>
</group>
<user><name>user4</name></user>
</users>' xml_string
from dual
),
xml_table as (
-- model of xmltable
select 10 id, xml_string xml_data from xmlsource union all
select 20 id, xml_string xml_data from xmlsource union all
select 30 id, xml_string xml_data from xmlsource
)
select *
from
XMLTable(
'
for $entry_user in $full_doc/full_list/list_entry/name_info
return <tuple>
<id>{data($entry_user/../#id_value)}</id>
<path>{$entry_user/name_path/text()}</path>
<name>{$entry_user/name_value/text()}</name>
</tuple>
'
passing (
select
XMLElement("full_list",
XMLAgg(
XMLElement("list_entry",
XMLAttributes(id as "id_value"),
XMLQuery(
'
declare function local:path-to-node( $nodes as node()* ) as xs:string* {
$nodes/string-join(ancestor-or-self::*/name(.), ''/'')
};(: function to construct path :)
for $i in $rdoc//name return <name_info><name_path>{local:path-to-node($i)}</name_path><name_value>{$i/text()}</name_value></name_info>
'
passing by value XMLParse(content xml_data) as "rdoc"
returning content
)
)
)
)
from xml_table
)
as "full_doc"
columns
id_val varchar2(4000) path '//tuple/id',
path_val varchar2(4000) path '//tuple/path',
name_val varchar2(4000) path '//tuple/name'
)
Update 3
As mentioned by #A.B.Cade in his comment, there are really simple way to join ID's with XQuery results.
Because I don't like external links in answers, code below represents his SQL fiddle, a little bit adapted to the data source from this answer:
with xmlsource as (
-- only for purpose to write long string only once
select '
<users><user><name>user1</name></user>
<user><name>user2</name></user>
<group>
<user><name>user3</name></user>
</group>
<user><name>user4</name></user>
</users>' xml_string
from dual
),
xml_table as (
-- model of xmltable
select 10 id, xml_string xml_data from xmlsource union all
select 20 id, xml_string xml_data from xmlsource union all
select 30 id, xml_string xml_data from xmlsource
)
select xd.id, x.* from
xml_table xd,
XMLTable(
'declare function local:path-to-node( $nodes as node()* ) as xs:string* {$nodes/string-join(ancestor-or-self::*/name(.), ''/'') }; for $i in $rdoc//name return <ret><name_path>{local:path-to-node($i)}</name_path>{$i}</ret> '
passing
XMLParse(content xd.xml_data
)
as "rdoc"
columns
name_path varchar2(4000) path '//ret/name_path',
name_value varchar2(4000) path '//ret/name'
) x

This is not perfect but can be a start:
Here is a sqlfiddle
with xslt as (
select '<?xml version="1.0" ?><xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<records>
<xsl:apply-templates/>
</records>
</xsl:template>
<xsl:template match="//name">
<columns>
<path>
<xsl:for-each select="ancestor-or-self::*">
<xsl:call-template name="print-step"/>
</xsl:for-each>
</path>
<value>
<xsl:value-of select="."/>
</value>
<xsl:apply-templates select="*"/>
</columns>
</xsl:template>
<xsl:template name="print-step">
<xsl:text>/</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>[</xsl:text>
<xsl:value-of select="1+count(preceding-sibling::*)"/>
<xsl:text>]</xsl:text>
</xsl:template>
</xsl:stylesheet>'
xsl from dual)
, xmldata as
(select xmltransform(xmltype('<?xml version="1.0"?>
<users><user><name>user1</name></user>
<user><name>user2</name></user>
<group>
<user><name>user3</name></user>
</group>
<user><name>user4</name></user>
</users>'), xmltype(xsl)) xd from xslt)
select XT.*
from xmldata c,
xmltable('$x//columns' passing c.xd
as "x"
columns
path_c VARCHAR2(4000) PATH 'path',
value_c VARCHAR2(4000) PATH 'value'
) as XT
This is what I tried to do:
Since you want the "path" I had to use xslt (credits to this post)
Then I used xmltransform for transforming your original xml with the xsl to the
desired output (path, value)
Then I used xmltable to read it as a table

This improves on above answer by A.B.Cade:
<xsl:template name="print-step">
<xsl:variable name="name" select="name()" />
<xsl:text>/</xsl:text>
<xsl:value-of select="$name"/>
<xsl:text>[</xsl:text>
<xsl:value-of select="1+count(preceding-sibling::*[name()=$name])"/>
<xsl:text>]</xsl:text>
</xsl:template>
With result:
/users[1]/user[1]/name[1] user1
/users[1]/user[2]/name[1] user2
/users[1]/group[1]/user[1]/name[1] user3
/users[1]/user[3]/name[1] user4
Instead of:
/users[1]/user[1]/name[1] user1
/users[1]/user[2]/name[1] user2
/users[1]/group[3]/user[1]/name[1] user3
/users[1]/user[4]/name[1] user4

Related

How to extract value of all the child nodes of a specific node (provided through input parameter) from XMLType Column in Oracle

One of our requirements is to get the value of all the child nodes of a given specific XML node.
I have got a solution for this using Microsoft SQL Server but I need the same in Oracle. Please see the below query.
Note: incase if there is more than one child node, the result should be the concatenation of all the individual child nodes'value.
select
REPLACE(Properties, 'utf-8', 'utf-16'),
CAST(REPLACE(Col1, 'utf-8', 'utf-16') as XML).value('(//*[local-name() = sql:variable("#var2")])[1]', 'varchar(200)')
from A
Following is a sample data/row from Col1:
<?xml version="1.0" encoding="utf-8"?><ConstantInputProperties xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Value xsi:type="xsd:int">0</Value></ConstantInputProperties>
here A is the table and Col1 is one of the columns of table A.
I tried to convert below Solution but it gives me the XML instead of values.
SELECT col1,
EXTRACT(XMLTYPE(col1), '(/*[local-name()="ConstantInputProperties"][1])')
FROM A
Example:
<?xml version="1.0" encoding="utf-8"?><ConstantInputProperties xmlns:xsd="w3.org/2001/XMLSchema" xmlns:xsi="w3.org/2001/XMLSchema-instance"><Value xsi:type="ArrayOfInt"><int>0</int><int>1</int></Value></ConstantInputProperties>
Expected Output 01
<?xml version="1.0" encoding="utf-8"?><ConstantInputProperties xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Value xsi:type="ArrayOfBoolean"><boolean>true</boolean><boolean>true</boolean><boolean>true</boolean><boolean>true</boolean><boolean>true</boolean></Value></ConstantInputProperties>
Expected Output truetruetruetruetrue
<?xml version="1.0" encoding="utf-8"?><ConstantInputProperties xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Value xsi:type="ArrayOfDecimal"><decimal>1.0000000000</decimal></Value></ConstantInputProperties>
Expected Output 1.0000000000
You could manipulate the XML inside an XPath with FLWOR syntax, but you could also use XMLTable to extract all the values; or rather, two XMLTables, one for a singleton element type and a second optional one for array expansion; get all the values as strings; and aggregate the results together:
select a.id,
listagg(coalesce(x1.value, x2.value), ' ')
within group (order by coalesce(x1.n, x2.n)) as result
from a
cross apply xmltable (
'(/*[local-name()=$var1][1])'
passing xmltype(col1), 'ConstantInputProperties' as "var1"
columns
n for ordinality,
value varchar2(30) path 'Value[#xsi:type="xsd:int"]',
array xmltype path 'Value[fn:starts-with(#xsi:type, "ArrayOf")]'
) x1
outer apply xmltable (
'Value/*'
passing array
columns
n for ordinality,
value varchar2(30) path '.'
) x2
group by a.id;
ID | RESULT
-: | :-----------------------
1 | 0
2 | 0 1
3 | true true true true true
4 | 1.0000000000
db<>fiddle
The n for ordinality just gives a numeric value that lets you keep the original sub-element order when aggregating (so you get 0 1 and not 1 0), If you don't want a spaces added to to the aggregated value then just change the second listagg argument from ' ' to null, though then you can't sell the difference between a singleton 10 and a pair of values with 1 and 0, so that doesn't seem very useful - not that an aggregated value seems that useful anyway really.
You could split into multiple sub-XMLTables, but that's probably not going to gain you anything here; db<>fiddle for info though.
can you suggest how to pass the ConstantInputProperties value as an argument and use it as a variable in function input in this case EXTRACT(XMLTYPE(col1), '(/[local-name()="ConstantInputProperties"]//text())')
The extract() function is deprecated. Use XMLQuery instead; for example:
select xmlquery(
'(/*[local-name()=$var1][1])/Value/text()'
passing xmltype(col1), 'ConstantInputProperties' as "var1"
returning content)
from a
Few examples:
with a as (
select q'[<?xml version="1.0" encoding="utf-8"?><ConstantInputProperties xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Value xsi:type="xsd:int">0</Value></ConstantInputProperties>
]' col1 from dual
)
select
x.*
from
a,
xmltable(
'//*[local-name()="ConstantInputProperties"][1]'
passing xmltype(a.col1)
columns
res xmltype path '.'
) x;
--Result:
RES
------------------------------------------------------------------------------
<ConstantInputProperties xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Value xsi:type="xsd:int">0</Value></ConstantInputProperties>
with a as (
select q'[<?xml version="1.0" encoding="utf-8"?><ConstantInputProperties xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Value xsi:type="xsd:int">0</Value></ConstantInputProperties>
]' col1 from dual
)
select
x.*
from
a,
xmltable(
'//*[local-name()="ConstantInputProperties"]/*/text()'
passing xmltype(a.col1)
columns
res xmltype path '.'
) x;
--Result:
RES
--------------------------------------------------------------
<Value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:int">0</Value>

Reading XML Namespace using Oracle SQL

My XML Looks like below
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<wfm:Statement xmlns:wfm="http://example.org/sample/xsd/sampleStatement/2013/05" xmlns:wfmMerchant="http://www.eds.com/sample/xsd/wfmMerchant/2012/03"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<wfm:StatementParameters>
<wfmMerchant:HierarchyCd>012-12-002-107-050</wfmMerchant:HierarchyCd>
</wfm:StatementParameters>
<StatementAmount>27.140</StatementAmount>
</wfm:Statement>
I am trying to get the value of StatementAmount tag using Oracle query like below
select MS.MERCHANT,MS.CHAIN_HIERARCHY_CD,MS.CYCLE_DATE, X.StatementAmount
FROM CHAIN_STATMNT_HIST_XML MS
CROSS JOIN XMLTABLE(XMLNAMESPACES('http://example.org/sample/xsd/sampleStatement/2013/05' AS "wfm", 'http://www.eds.com/sample/xsd/wfmMerchant/2012/03' as wfmmerchant
default 'http://www.w3.org/2001/XMLSchema-instance')
,'/wfm:Statement/StatementAmount' passing xmltype(MS.XML_REPORT)
columns StatementAmount varchar(18) path '.')X
But, I am always getting NULL. I can able to successfully retrieve Hierarchy value from the XML which has namespace. But StatementAmount tag doesn't have any namespace and I have trouble retrieving it.
Can someone help with this issue ?
Your default namespace declaration seems to be causing the problem; without that (and ignoring wfmMerchant):
-- CTE for sample data
with CHAIN_STATMNT_HIST_XML (merchant, chain_hierarchy_cd, cycle_date, XML_REPORT) as (
select 1, 2, sysdate, '<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<wfm:Statement xmlns:wfm="http://example.org/sample/xsd/sampleStatement/2013/05" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<wfm:StatementParameters>
<!-- excluding this as namespace not provided -->
<!-- <wfmMerchant:HierarchyCd>012-12-002-107-050</wfmMerchant:HierarchyCd> -->
</wfm:StatementParameters>
<StatementAmount>27.140</StatementAmount>
</wfm:Statement>' from dual
)
-- actual query
select MS.MERCHANT,MS.CHAIN_HIERARCHY_CD,MS.CYCLE_DATE, X.StatementAmount
FROM CHAIN_STATMNT_HIST_XML MS
CROSS JOIN XMLTABLE(
XMLNAMESPACES('http://example.org/sample/xsd/sampleStatement/2013/05' AS "wfm"),
'/wfm:Statement/StatementAmount' passing xmltype(MS.XML_REPORT)
columns StatementAmount varchar(18) path '.'
) X
/
MERCHANT CHAIN_HIERARCHY_CD CYCLE_DATE STATEMENTAMOUNT
---------- ------------------ ---------- ------------------
1 2 2018-09-04 27.140
I'm not sure why you would use varchar2(18) as the datatype rather than number; and if there is only one statement amount per statement you could do:
select MS.MERCHANT,MS.CHAIN_HIERARCHY_CD,MS.CYCLE_DATE, X.StatementAmount
FROM CHAIN_STATMNT_HIST_XML MS
CROSS JOIN XMLTABLE(
XMLNAMESPACES('http://example.org/sample/xsd/sampleStatement/2013/05' AS "wfm"),
'/wfm:Statement' passing xmltype(MS.XML_REPORT)
columns StatementAmount number path 'StatementAmount'
) X

How to pull XML key "value" from SQL CLOB

I am attempting to extract information from XML stored in a CLOB column. I've searched the forums and thus far have been unable to get the data to pull as needed. I have a basic understanding of SQL but this is beyond me.
The XML is similar to the following:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Header>
<OrderNum value="12354321"/>
<ExtractDate value="11-30-2012"/>
<RType value="Status"/>
<Company value="Company"/>
</Header>
<Body>
<Status>
<Order>
<ActivityType value="ValidateRequest"/>
<EndUser>
<Name value="Schmo, Joe"/>
<Address>
<SANO value="12345"/>
<SASN value="Mickey Mouse"/>
<SATH value="Lane"/>
<SASS value="N"/>
<City value="Orlando"/>
<State value="FL"/>
<Zip value="34786"/>
<Number value="5550000"/>
</Address>
</EndUser>
<COS value="1"/>
<TOS value="3"/>
<MainNumber value="5550000"/>
</Order>
<ErrorCode value="400"/>
<ErrorMessage value="RECEIVED"/>
</Status>
</Body>
</Response>
I want to get the values under "Address".
I've tried the following but it returns "NULL".
SELECT EXTRACTVALUE(XMLTYPE(RESPONSE_CLOB),'/Response/Body/Status/Order/EndUser/Address/SANO') AS SANO
FROM RESPONSE_TABLE
WHERE ROWNUM < 2
I am trying to get it so I can pull the "12345" assigned as "value" in "SANO" (ultimately getting the value for other fields, but want to at least get the one working first).
You're currently retrieving the text value of the node, but 12345 is the value attribute of the element rather than its text content. So you would need to use the #attribute syntax, i.e.:
SELECT EXTRACTVALUE(XMLTYPE(RESPONSE_CLOB),'/Response/Body/Status/Order/EndUser/Address/SANO/#value') AS SANO
FROM RESPONSE_TABLE
WHERE ROWNUM < 2;
SANO
--------------------
12345
But extractvalue is deprecated; assuming you're on a recent version of Oracle it would be better to use an XMLQuery:
SELECT XMLQUERY(
'/Response/Body/Status/Order/EndUser/Address/SANO/#value'
PASSING XMLTYPE(RESPONSE_CLOB)
RETURNING CONTENT
) AS SANO
FROM RESPONSE_TABLE
WHERE ROWNUM < 2;
You may find it even easier to use an XMLTable - necessary if an XML document has multiple Address nodes, but even with just one pulling the values out as columns is less repetitive, and it makes it easier to retrieve suitable data types:
select x.*
from response_table rt
cross join xmltable(
'/Response/Body/Status/Order/EndUser/Address'
passing xmltype(rt.response_clob)
columns sano number path 'SANO/#value',
sasn varchar2(30) path 'SASN/#value',
sath varchar2(10) path 'SATH/#value'
-- etc.
) x
where rownum < 2;
SANO SASN SATH
-------------------- ------------------------------ ----------
12345 Mickey Mouse Lane
Read more about using these functions to query XML data.

getting name and value from xmltype attribute in oracle

Description
Hello, I have a problem with extracting attribute names and values from XMLType value in Oracle.
Basically, I have a table, let's say TableA, which has a XMLType column, let's call it TableA_config. Values in TableA_config have structure like this:
<TableAConfig someAttribute1="value1" someAttribute2="value2" someAttribute3="value3" />. The number of attributes and their names may vary and are not known beforehand.
What I need to do is (for each row) create new XMLElement called TableAConfigList, which contains XMLElements called TableAConfig and each of those has two attributes: name and value. Now, number of TableAConfig nodes must be equal to number of attributes in TableA_config column, and each holds name of corresponding attribute in name attribute and its value in value attribute.
Example
From:
<TableAConfig someAttribute1="value1" someAttribute2="value2" someAttribute3="value3" />
I should get:
<TableAConfigList>
<TableAConfig name="someAttribute1" value="value1"/>
<TableAConfig name="someAttribute2" value="value2"/>
<TableAConfig name="someAttribute3" value="value3"/>
</TableAConfigList>
What I tried
I came up with idea to create a XMLTable from TableA_config column value and in it create two columns, which I can later select. It looks like this (it is a fragment of a bigger query):
SELECT XMLElement("TableAConfigList",
(SELECT
XMLAgg(
XMLElement("TableAConfig",
XMLAttributes(
tmp."attr_name" as "name",
tmp."attr_text" as "value"
)
)
) from XMLTable('/TableAConfig/#*'
passing TableA.TableA_config
columns
"attr_name" varchar(30) path 'name()',
"attr_text" varchar(30) path 'text()'
) tmp
)
) from dual
But now i get:
<TableAConfigList>
<TableAConfig name="someAttribute1"></TableAConfig>
<TableAConfig name="someAttribute2"></TableAConfig>
<TableAConfig name="someAttribute3"></TableAConfig>
</TableAConfigList>
There is no value. However, if I remove name from XMLAttributes it shows up. From:
SELECT XMLElement("TableAConfigList",
(SELECT
XMLAgg(
XMLElement("TableAConfig",
XMLAttributes(
tmp."attr_text" as "value"
)
)
) from XMLTable('/TableAConfig/#*'
passing TableA.TableA_config
columns
"attr_name" varchar(30) path 'name()',
"attr_text" varchar(30) path 'text()'
) tmp
)
) from dual
I get:
<TableAConfigList>
<TableAConfig value="value1"></TableAConfig>
<TableAConfig value="value2"></TableAConfig>
<TableAConfig value="value3"></TableAConfig>
</TableAConfigList>
I thought that maybe, for some reason, there can only be one attribute created this way, but if I add a new one by hardcoding it, it shows up in result, like this:
SELECT XMLElement("TableAConfigList",
(SELECT
XMLAgg(
XMLElement("TableAConfig",
XMLAttributes(
tmp."attr_text" as "value",
'testValue' as "testAttribute"
)
)
) from XMLTable('/TableAConfig/#*'
passing TableA.TableA_config
columns
"attr_name" varchar(30) path 'name()',
"attr_text" varchar(30) path 'text()'
) tmp
)
) from dual
Result:
<TableAConfigList>
<TableAConfig value="value1" testAttribute="testValue"></TableAConfig>
<TableAConfig value="value2" testAttribute="testValue"></TableAConfig>
<TableAConfig value="value3" testAttribute="testValue"></TableAConfig>
</TableAConfigList>
Putting in XMLAttributes both columns and hardcoded one gives me name and testAttribute, but no value.
Could someone tell me is it because I miss something terribly obvious, is it a bug or am I doing it completely wrong. I am pretty new to Oracle and PL/SQL and could really appreciate your help. Thanks!
You were almost there with your first attempt. While evaluating the XPath, when you are inside the attribute list with /TableAConfig/#*, you don't need text() to get the value of the attribute inside it. You are already at the attribute level so using just a "dot" . for current node would be sufficient.
So try something like this -
SELECT XMLElement("TableAConfigList",
(SELECT
XMLAgg(
XMLElement("TableAConfig",
XMLAttributes(
tmp."attr_name" as "name",
tmp."attr_text" as "value"
)
)
) from XMLTable('/TableAConfig/#*'
passing TableA.TableA_config
columns
"attr_name" varchar(30) path 'name()',
"attr_text" varchar(30) path '.'
) tmp
)
) from dual
The only difference from your first attempt is the xpath of the value attribute.
You can use XMLTRANSFORM too:
select xmltransform(
xmltype('<TableAConfig someAttribute1="value1" someAttribute2="value2" someAttribute3="value3" />'),
xmltype('<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="TableAConfig">
<TableAConfigList>
<xsl:for-each select="#*">
<xsl:element name="TableAConfig" >
<xsl:attribute name="name">
<xsl:value-of select="name()"/>
</xsl:attribute>
<xsl:attribute name="value">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:element>
</xsl:for-each>
</TableAConfigList>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>'))
from dual

SQL:Looping and Reading from XML type

i have set of records from XML type and i need to loop through the Nodes and extract data from them
<Data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<OP xmlns="http://tempuri.org/Types.xsd">
<ID>
<FDSerial>00000008</FDSerial>
<Type>1</Type>
</ID>
<Param>1</Param>
<OperationName>ReadData</OperationName>
</OP>
<OP xmlns="http://tempuri.org/Types.xsd">
<ID>
<FDSerial>00000009</FDSerial>
<Type>1</Type>
</ID>
<Param>1</Param>
<OperationName>ReadData</OperationName>
</OP>
</Data>
i already read from the record but i need to loop through the Nodes
;WITH XMLNAMESPACES('http://tempuri.org/Types.xsd' as ns)
SELECT Data.value('/Data[1]/ns:Op[1]/ns:ID[1]/ns:FDSerial[1]', 'varchar(50)')
as Serial
FROM [dbo].[DB]
what i need to replace the # 1 with i in a loop
Update:
i updated the xml data.
the expected from this data is the Nodes value of the FDSerial.
i hope i explained my issue clearly
You don't need a loop at all. Use nodes() in a cross apply to shred on /Data/OP.
with xmlnamespaces('http://tempuri.org/Types.xsd' as ns)
select T.X.value('(ns:ID/ns:FDSerial/text())[1]', 'varchar(50)') as Serial
from dbo.DB
cross apply DB.Data.nodes('/Data/ns:OP') as T(X)
this will work also
;WITH XMLNAMESPACES('http://tempuri.org/Types.xsd' as ns)
SELECT Data.value('(Data/ns:Op/ns:ID/ns:FDSerial/text())[1]', 'varchar(50)')
as Serial
FROM [dbo].[DB]