Home > Net >  SQL to Parse XML
SQL to Parse XML

Time:02-05

Can someone please help... I cannot seem to figure this out... I need to parse this using T-SQL. I have it saved as a file in the C:\Temp directory, named "OpenPos.XML". Any help would be very greatly appreciated. I need to be able to parse the XML and write it to a SQL table.

If I do an outer apply at all levels, it applies every PO # to every line instead of just for the lines related to that PO #.

XML File:

<?xml version="1.0" encoding="utf-8"?>
<acXML lang="en-us" xmlns="https://www.autocrib.net/acXMLSchema.xsd">
  <Header>
    <From>
      <Company>Rolls Royce ATC (Indianapolis)</Company>
      <Identity>rollsroyceatc-indianapolis</Identity>
      <DatabaseName>AutoCribNet2</DatabaseName>
    </From>
  </Header>
  <Request>
    <OpenPurchaseOrderRequest ReqType="GET">
      <PoNo>1716W</PoNo>
      <ExternalPoNo />
      <LineItems>
        <Item>
          <Line>1</Line>
          <TagNo>1716</TagNo>
          <VendorID>QMS</VendorID>
          <ItemID>CARD BC6266</ItemID>
          <ItemType>Expendable</ItemType>
          <ItemRFID />
          <Station>01</Station>
          <Bin>0825-04-B-06</Bin>
          <OrderQty>1</OrderQty>
          <Received>1</Received>
          <ReceivedBurn>0</ReceivedBurn>
          <PackQty>1</PackQty>
          <UnitCost>0.0000</UnitCost>
          <UnitPrice>0.0000</UnitPrice>
          <Lot />
          <IsSpotBuy>False</IsSpotBuy>
          <SpotTranCode>0</SpotTranCode>
          <Inspect>False</Inspect>
          <InspDate />
          <InspOnHand>0</InspOnHand>
          <InspBurn>0</InspBurn>
          <OrderDate>01-13-2022</OrderDate>
          <DueDate>01-25-2022</DueDate>
          <PromiseDt>01-25-2022</PromiseDt>
          <ReceiveDt />
          <Department />
          <Job />
          <Machine />
          <Reason />
          <Part />
          <Processed>False</Processed>
        </Item>
      </LineItems>
    </OpenPurchaseOrderRequest>
    <OpenPurchaseOrderRequest ReqType="GET">

SQL: 
--Open POs
SELECT PO_X = CAST(BulkColumn AS xml)
INTO #PO
FROM OPENROWSET(BULK 'C:\AutoCrib WebServices\XML Files\ATC\OpenPOs.XML', SINGLE_CLOB) t 

 SELECT [Company] = p.PO_X.value('(//*:Header/*:From/*:Company)[1]', 'varchar(150)')
     , [Identity] = f.value('(*:Identity)[1]', 'varchar(200)')
     , [DatabaseNM] = f.value('(*:DatabaseName)[1]', 'varchar(50)')
     , [PoNo] = r.value('(*:PoNo)[1]', 'varchar(10)')
     , [ItemLine] = i.value('(*:Line)[1]', 'int')
     , [ItemTagNo] = i.value('(*:TagNo)[1]', 'varchar(10)')
     , [ItemVendorID] = i.value('(*:VendorID)[1]', 'varchar(100)')
     , [ItemID] = i.value('(*:ItemID)[1]', 'varchar(30)')
     , [ItemRFID] = i.value('(*:ItemRFID)[1]', 'varchar(50)')
     , [ItemStation] = i.value('(*:Station)[1]', 'varchar(5)')
     , [ItemBin] = i.value('(*:Bin)[1]', 'varchar(30)')
     , [ItemOrderQty] = i.value('(*:OrderQty)[1]', 'int')
     , [ItemReceived] = i.value('(*:Received)[1]', 'int')
     , [ItemReceivedBurn] = i.value('(*:ReceivedBurn)[1]', 'int')
     , [ItemPackQty] = i.value('(*:PackQty)[1]', 'int')
     , [ItemUnitCost] = i.value('(*:UnitCost)[1]', 'money')
     , [ItemUnitPrice] = i.value('(*:UnitPrice)[1]', 'money')
     , [ItemOrderDate] = i.value('(*:OrderDate)[1]', 'datetime')
     , [ItemDueDate] = i.value('(*:DueDate)[1]', 'datetime')
     , [ItemPromiseDate] = i.value('(*:PromiseDt)[1]', 'datetime')
     , [ItemReceiveDate] = i.value('(*:ReceiveDt)[1]', 'datetime')
     , [ItemProcessed] = i.value('(*:Processed)[1]', 'varchar(10)')
FROM #PO p
    OUTER APPLY p.PO_X.nodes('//*:Header/*:From') a(f)
    OUTER APPLY p.PO_X.nodes('//*:Request/*:OpenPurchaseOrderRequest') c(r)
    OUTER APPLY p.PO_X.nodes('//*:Request/*:OpenPurchaseOrderRequest/*:LineItems/*:Item') l(i) 
DROP TABLE #PO

CodePudding user response:

Start with loading the file. This uses OPENROWSET, but you might find BULK INSERT more flexible.

    SELECT DepX = CAST(BulkColumn AS xml)
    INTO #Departments
      FROM OPENROWSET(BULK 'C:\Temp\Departments.XML', SINGLE_CLOB) t 
    
    --SINGLE_CLOB|SINGLE_NCLOB for Ascii vs Unicode

Now, we can query the xml

    SELECT [From.Company] = d.DepX.value('(//*:Header/*:From/*:Company)[1]', 'varchar(99)')
            /* Shorter paths if we OUTER APPLY the root we're interested in */
         , [From.Company Shortcut] = f.value('(*:Company)[1]', 'varchar(99)')
      FROM #Departments d
      OUTER APPLY d.DepX.nodes('//*:Header/*:From') a(f)

Results

From.Company From.Company Shortcut
Test Company (Indianapolis) Test Company (Indianapolis)

For help with xml shredding, try Jacob Sebastian's SELECT * FROM XML The output is helpful, but taking the time to go through and understand how it works is very educational.

This uses namespace wildcard *:
More complex xml might require WITH XMLNAMESPACE

CodePudding user response:

I was finally able to figure it out. I was missing the namespace. Here's my SQL logic:

DECLARE @XML XML = 
    (SELECT *
     FROM OPENROWSET(BULK 'C:\Temp\OpenPOs.XML', SINGLE_CLOB) t)

;WITH XMLNAMESPACES (DEFAULT 'https://www.autocrib.net/acXMLSchema.xsd')
SELECT A.evnt.value('(PoNo/text())[1]','varchar(10)') AS Event_DriverId
      ,B.rec.value('(Line/text())[1]','int') AS Record_RecordId 
FROM @XML.nodes('/acXML/Request/OpenPurchaseOrderRequest') A(evnt)
    OUTER APPLY A.evnt.nodes('LineItems/Item') B(rec);
  •  Tags:  
  • Related