Home > Software engineering >  XML Parse in T-SQL
XML Parse in T-SQL

Time:06-19

I am trying to parse XML document inside of T-SQL. XML Document look like when there is some clients:

<?xml version="1.0" encoding="utf-16"?> 
<ArrayOfServerSettings>
   <ServerSettings>
     <Address>10.0.1.1</Address>
     <Nodes>
        <NodeSettings>
            <PortNumber>5000</PortNumber>
            <ClientIds>
                <int>1</int>
                <int>2</int>
                <int>3</int>
            </ClientIds>
        </NodeSettings>
      </Nodes>
   </ServerSettings>
</ArrayOfServerSettings>

if there is no any clients, it looks like

<?xml version="1.0" encoding="utf-16"?> 
<ArrayOfServerSettings>
   <ServerSettings>
     <Address>10.0.1.1</Address>
     <Nodes>
        <NodeSettings>
            <PortNumber>5000</PortNumber>
            <ClientIds />
        </NodeSettings>
      </Nodes>
   </ServerSettings>
</ArrayOfServerSettings>

In the first case, the table should look like

Address     PortNumber     ClientId
10.0.1.1      5000           1
10.0.1.1      5000           2
10.0.1.1      5000           3

When there is no client I should parse them like

Address     PortNumber     ClientId
10.0.1.1      5000           0

Here is my t-sql statements

declare @xml XML
set @xml = N'<?xml version="1.0" encoding="utf-16"?>
<ArrayOfCalculationServerSettings>
   <CalculationServerSettings>
      <Address>10.0.1.1</Address>
      <Nodes>
         <NodeSettings>
            <PortNumber>10009</PortNumber>
            <ClientIds>
               <int>1</int>
               <int>2</int>
               <int>3</int>
            </ClientIds>
         </NodeSettings>
      </Nodes>
  </CalculationServerSettings>

'

DECLARE @DocID INT 
EXEC sp_xml_preparedocument @DocID OUTPUT, @xml

SELECT *   
FROM
    OPENXML(@DocID, '/ArrayOfServerSettings/ServerSettings/Nodes/NodeSettings/ClientIds/int', 1)
    WITH (
        Address NVARCHAR(256) '../../../../Address[1]',
        PortNumber    INT           '../../PortNumber[1]',
        ClientID      INT           '.'
    ) AS D0

EXEC sp_xml_removedocument @DocID

But my approach is not working for the second option

CodePudding user response:

If we can assume that you have valid XML (yours is not), and that you only have 1 PortNumber node, you could do this:

declare @xml XML
set @xml = N'<?xml version="1.0" encoding="utf-16"?>
<ArrayOfCalculationServerSettings>
   <CalculationServerSettings>
      <Address>10.0.1.1</Address>
      <Nodes>
         <NodeSettings>
            <PortNumber>10009</PortNumber>
            <ClientIds>
               <int>1</int>
               <int>2</int>
               <int>3</int>
            </ClientIds>
         </NodeSettings>
      </Nodes>
  </CalculationServerSettings>
</ArrayOfCalculationServerSettings>'; --This is missing in your XML

SELECT ACSS.CSS.value('(Address/text())[1]','nvarchar(15)') AS Address,
       ACSS.CSS.value('(Nodes/NodeSettings/PortNumber/text())[1]','int') AS PortNumber, --I assume always the same port number
       ISNULL(CS.I.value('text()[1]','int'),0) AS int
FROM @xml.nodes('ArrayOfCalculationServerSettings/CalculationServerSettings') ACSS(CSS)
     OUTER APPLY ACSS.CSS.nodes('Nodes/NodeSettings/ClientIds/int')CS(I);

If you have multiple port numbers, with more int values, then you'll need to do some further nesting of the nodes methods.

  • Related