OPENXML con xmlns: dt
-
10-07-2019 - |
Domanda
Usa OPENXML per ottenere l'elemento dt in MSSQL 2005. Come posso ottenere xmlns: elemento dt in xml? Ad esempio, ottieni un set di risultati di due righe che elenca l'ID prodotto e il codice paese.
121403 GBR
121403 USA
declare @xmldata xml
set @xmldata =
'<?xml version="1.0"?>
<data xmlns="http://www.aaa.com/master_browse_response" xmlns:dt="http://www.aaa.com/DataTypes">
<products>
<product>
<product_id><![CDATA[121403]]></product_id>
<countries>
<dt:country>GBR</dt:country>
<dt:country>USA</dt:country>
</countries>
</product>
</products>
</data>'
DECLARE @hDoc int, @rootxmlns varchar(100)
SET @rootxmlns = '<root xmlns:hm="http://www.aaa.com/master_browse_response"/>'
EXEC sp_xml_preparedocument @hDoc OUTPUT, @xmldata, @rootxmlns
SELECT *
FROM OPENXML(@hDoc, '//hm:product',2)
WITH ([hm:product_id] int , [hm:countries] varchar(100))
--clean up
EXEC sp_xml_removedocument @hDoc
Ecco una soluzione che conosco usando xmlEdgeTable, ma sto cercando una soluzione migliore.
DECLARE @hDoc int, @rootxmlns varchar(100)
SET @rootxmlns = '<root xmlns:hm="http://www.aaa.com/master_browse_response"/>'
EXEC sp_xml_preparedocument @hDoc OUTPUT, @xmldata, @rootxmlns
CREATE TABLE #xmlEdgeTable
(
id int,
parentid int,
localname varchar(20),
[text] varchar(20)
)
INSERT INTO #xmlEdgeTable
SELECT id, parentid,localname, cast([text] as varchar(20))
FROM OPENXML(@hDoc, '//hm:product',2)
SELECT t6.text, t2.text FROM #xmlEdgeTable AS t1 INNER JOIN
#xmlEdgeTable AS t2 ON t1.id = t2.parentid INNER JOIN
#xmlEdgeTable AS t3 ON t3.id = t1.parentid INNER JOIN
#xmlEdgeTable AS t4 ON t4.id = t3.parentid INNER JOIN
#xmlEdgeTable AS t5 ON t4.id = t5.parentid INNER JOIN
#xmlEdgeTable AS t6 ON t5.id = t6.parentid
WHERE t1.localname = 'country' and t5.localname ='product_id'
--clean up
EXEC sp_xml_removedocument @hDoc
DROP TABLE #xmlEdgeTable
Soluzione
C'è un motivo particolare per cui devi usare OPENXML per farlo? Puoi facilmente ottenere le informazioni con un XQUERY nel 2005 in questo modo:
declare @xmldata xml
set @xmldata =
'<data xmlns="http://www.aaa.com/master_browse_response" xmlns:dt="http://www.aaa.com/DataTypes">
<products>
<product>
<product_id>121403</product_id>
<countries>
<dt:country>GBR</dt:country>
<dt:country>USA</dt:country>
</countries>
</product>
</products>
</data>'
;WITH XMLNAMESPACES
(
DEFAULT 'http://www.aaa.com/master_browse_response',
'http://www.aaa.com/DataTypes' as dt
)
SELECT x.c.value('(../../product_id)[1]', 'varchar(100)') as product_id,
x.c.value('(.)[1]', 'varchar(100)') as country
FROM @xmldata.nodes('/data/products/product/countries/dt:country') x(c)
Le nuove funzionalità di XQUERY sono una scelta molto migliore per risolvere il tuo problema.
EDIT: La stessa soluzione con OPENXML sarebbe:
declare @xmldata xml
set @xmldata =
'<data xmlns="http://www.aaa.com/master_browse_response" xmlns:dt="http://www.aaa.com/DataTypes">
<products>
<product>
<product_id>121403</product_id>
<countries>
<dt:country>GBR</dt:country>
<dt:country>USA</dt:country>
</countries>
</product>
</products>
</data>'
DECLARE @hDoc int, @rootxmlns varchar(100)
SET @rootxmlns = '<root xmlns:hm="http://www.aaa.com/master_browse_response" xmlns:dt="http://www.aaa.com/DataTypes"/>'
EXEC sp_xml_preparedocument @hDoc OUTPUT, @xmldata, @rootxmlns
SELECT *
FROM OPENXML(@hDoc, '//hm:product/hm:countries/dt:country',2)
WITH(Country varchar(100) '.',
Product_ID varchar(100) '../../hm:product_id')
EXEC sp_xml_removedocument @hDoc
Altri suggerimenti
Per un piccolo set di dati, non vi è alcuna grande differenza tra XQuery e OPENXML
Ecco i risultati per analizzare un file xml da 6,5 ??MB per ottenere 27.615 righe:
- OPENXML con dt: 2 secondi
- OPENXML con #xmlEdgeTable: 6 minuti 38 secondi
- XQuery: 24 minuti 54 secondi