XPath e seus valores no XML usando PL/SQL
Olá camaradas !
Me perguntaram como varrer um XML, exibir todos os XPaths e mostrar os seus respectivos valores. Isso após ler esse mesmo XML de um campo na tabela.
Isso não é algo de outro mundo, mas percebi que muitos não sabiam exatamente como fazer isso. Então decidi escrever um pequeno tutorial de como conseguir esse feito. 🙂
Primeiramente, vamos criar a nossa tabela:
CREATE TABLE tab_xml (
nf SYS.XMLTYPE
);
Table TAB_XML created.
Para testar, precisaremos de um XML. Existe uma maneira simples de gerarmos um, que é fazer um SELECT em uma tabela utilizando o hint /*xml*/.
Usarei uma tabela qualquer nesse teste.
SELECT /*xml*/ periodo,id_source,id,flexfield2,flexfield4
FROM <tabela>
WHERE periodo = '04/2014'
O resultado é:
<?xml version="1.0" encoding="UTF-8" ?>
<RESULTS>
<ROW>
<COLUMN NAME="PERIODO"><![CDATA[04/2014]]></COLUMN>
<COLUMN NAME="ID_SOURCE"><![CDATA[100]]></COLUMN>
<COLUMN NAME="ID"><![CDATA[1]]></COLUMN>
<COLUMN NAME="FLEXFIELD2"><![CDATA[202168]]></COLUMN>
<COLUMN NAME="FLEXFIELD4"><![CDATA[30/04/2014]]></COLUMN>
</ROW>
<ROW>
<COLUMN NAME="PERIODO"><![CDATA[04/2014]]></COLUMN>
<COLUMN NAME="ID_SOURCE"><![CDATA[100]]></COLUMN>
<COLUMN NAME="ID"><![CDATA[2]]></COLUMN>
<COLUMN NAME="FLEXFIELD2"><![CDATA[202167]]></COLUMN>
<COLUMN NAME="FLEXFIELD4"><![CDATA[30/04/2014]]></COLUMN>
</ROW>
</RESULTS>
Se quiser saber mais sobre esse tipo de hint, leia o meu artigo abaixo:
Agora que temos o nosso XML, vamos inserí-lo na tabela que criamos:
DECLARE
v_xml SYS.XMLTYPE;
v_doc CLOB;
BEGIN
-- XMLTYPE created from a CLOB
v_doc := '<?xml version="1.0" encoding="UTF-8" ?>
<RESULTS>
<ROW>
<COLUMN NAME="PERIODO"><![CDATA[04/2014]]></COLUMN>
<COLUMN NAME="ID_SOURCE"><![CDATA[100]]></COLUMN>
<COLUMN NAME="ID"><![CDATA[1]]></COLUMN>
<COLUMN NAME="FLEXFIELD2"><![CDATA[202168]]></COLUMN>
<COLUMN NAME="FLEXFIELD4"><![CDATA[30/04/2014]]></COLUMN>
</ROW>
<ROW>
<COLUMN NAME="PERIODO"><![CDATA[04/2014]]></COLUMN>
<COLUMN NAME="ID_SOURCE"><![CDATA[100]]></COLUMN>
<COLUMN NAME="ID"><![CDATA[2]]></COLUMN>
<COLUMN NAME="FLEXFIELD2"><![CDATA[202167]]></COLUMN>
<COLUMN NAME="FLEXFIELD4"><![CDATA[30/04/2014]]></COLUMN>
</ROW>
</RESULTS>';
v_xml := SYS.XMLTYPE.createXML(v_doc);
INSERT INTO tab_xml(nf) VALUES (v_xml);
COMMIT;
END;
/
PL/SQL procedure successfully completed.
Ótimo ! Agora vamos a parte divertida. Vamos rodar o nosso script para destrinchar o XPath e seus valores:
WITH params AS
(
SELECT nf p_xml
FROM tab_xml
)
SELECT element_path
,element_text
FROM XMLTable
(
'
for $i in $doc/descendant-or-self::*
return <element>
<element_path> {$i/string-join(ancestor-or-self::*/name(.), ''/'')} </element_path>
<element_content> {$i/text()}</element_content>
</element>
'
PASSING
(
SELECT p_xml
FROM params
) AS "doc"
COLUMNS
element_path varchar2(4000) path '//element_path',
element_text varchar2(4000) path '//element_content'
)
E o resultado é:
Todos os XPath e seus valores foram listados !
Creio que não escolhi o melhor modelo de XML, para demonstrar o resultado. Então vamos mudar um pouquinho ele:
<?xml version="1.0" encoding="UTF-8" ?>
<RESULTS>
<ROW>
<PERIODO><![CDATA[04/2014]]></PERIODO>
<ID_SOURCE><![CDATA[100]]></ID_SOURCE>
<ID><![CDATA[1]]></ID>
<FLEXFIELD2><![CDATA[202168]]></FLEXFIELD2>
<FLEXFIELD4><![CDATA[30/04/2014]]></FLEXFIELD4>
</ROW>
<ROW>
<PERIODO><![CDATA[05/2014]]></PERIODO>
<ID_SOURCE><![CDATA[200]]></ID_SOURCE>
<ID><![CDATA[1]]></ID>
<FLEXFIELD2><![CDATA[202170]]></FLEXFIELD2>
<FLEXFIELD4><![CDATA[30/05/2014]]></FLEXFIELD4>
</ROW>
</RESULTS>
Agora vamos limpar a nossa tabela:
DELETE FROM tab_xml
/
1 row deleted.
Ótimo ! Agora vamos inserir o nosso novo XML:
DECLARE
v_xml SYS.XMLTYPE;
v_doc CLOB;
BEGIN
-- XMLTYPE created from a CLOB
v_doc := '<?xml version="1.0" encoding="UTF-8" ?>
<RESULTS>
<ROW>
<PERIODO><![CDATA[04/2014]]></PERIODO>
<ID_SOURCE><![CDATA[100]]></ID_SOURCE>
<ID><![CDATA[1]]></ID>
<FLEXFIELD2><![CDATA[202168]]></FLEXFIELD2>
<FLEXFIELD4><![CDATA[30/04/2014]]></FLEXFIELD4>
</ROW>
<ROW>
<PERIODO><![CDATA[05/2014]]></PERIODO>
<ID_SOURCE><![CDATA[200]]></ID_SOURCE>
<ID><![CDATA[1]]></ID>
<FLEXFIELD2><![CDATA[202170]]></FLEXFIELD2>
<FLEXFIELD4><![CDATA[30/05/2014]]></FLEXFIELD4>
</ROW>
</RESULTS>';
v_xml := SYS.XMLTYPE.createXML(v_doc);
INSERT INTO tab_xml(nf) VALUES (v_xml);
COMMIT;
END;
/
PL/SQL procedure successfully completed.
Executando novamente o nosso script:
WITH params AS
(
SELECT nf p_xml
FROM tab_xml
)
SELECT element_path
,element_text
FROM XMLTable
(
'
for $i in $doc/descendant-or-self::*
return <element>
<element_path> {$i/string-join(ancestor-or-self::*/name(.), ''/'')} </element_path>
<element_content> {$i/text()}</element_content>
</element>
'
PASSING
(
SELECT p_xml
FROM params
) AS "doc"
COLUMNS
element_path varchar2(4000) path '//element_path',
element_text varchar2(4000) path '//element_content'
)
Creio que visualmente, ficou melhor para entender o resultado ! 🙂
Tenho certeza de que pensou algo do tipo “Legal, era o resultado que eu precisava, mas que código é esse ?!?“.
Principalmente nessa parte:
for $i in $doc/descendant-or-self::*
return <element>
<element_path> {$i/string-join(ancestor-or-self::*/name(.), ''/'')} </element_path>
<element_content> {$i/text()}</element_content>
</element>
Essa parte é em XQuery ! Mas o que é XQuery ?
XQuery é uma linguagem de consulta, com alguns recursos de programação, que é projetada para fazer consultas em coleções de dados em XML. Ela é semanticamente similar ao SQL. (Obrigado Wikipédia !)
Com o XQuery, é possível extrair praticamente qualquer tipo de informação de um XML. Além de ser extremamente rápido !
Utilizando XQuery, já consegui decompor arquivos XMLs enormes com milhares de itens, em questão de segundos !
Se você quiser se aprofundar mais em XQuery, deixarei os links nas referências abaixo !
Um grande abraço !
Referências