Harry
Harry

Reputation: 2941

SQL Server 2016 extract info from XML

I've been through various posts on the same subject but I can't seem to be able to get to the data elements in my XML file.

Here is a snippet of my XML :

   <ed:Certificate xmlns="http://sancrt.mpi.govt.nz/ecert/2013/ed-multiple-submission-schema.xsd" xmlns:ed="http://sancrt.mpi.govt.nz/ecert/2013/ed-submission-schema.xsd"> <ed:Status Code="39">Approved</ed:Status>   <ed:LastUpdatedDate>2021-03-10T14:20:55+13:00</ed:LastUpdatedDate>   <ed:Identifiers>
        <ed:CertificateID>NZL2021/MEABC/26913T</ed:CertificateID>
        <ed:TemplateID>ED1.6</ed:TemplateID>   </ed:Identifiers>   <ed:Exhausted>true</ed:Exhausted>   <ed:AutoApproval>false</ed:AutoApproval>   <ed:DepartureDate>2021-03-10</ed:DepartureDate>   <ed:Parties>
        <ed:ConsignorID>MEABC</ed:ConsignorID>
        <ed:ConsigneeID>FLIGHT1</ed:ConsigneeID>   </ed:Parties>   <ed:Transport>
        <ed:Ports>
          <ed:LoadingPortID>NZTRG</ed:LoadingPortID>
        </ed:Ports>
        <ed:FinalDestination>OAKLAND, United States</ed:FinalDestination>
        <ed:TransportMode>1</ed:TransportMode>
        <ed:LocalCarrier>MDH2</ed:LocalCarrier>
        <ed:CarrierName> Ever Given</ed:CarrierName>
        <ed:ConveyanceReference>V1234</ed:ConveyanceReference>   </ed:Transport>   <ed:Remarks>
        <ed:Remark>
          <ed:RemarkType>Unofficial Information</ed:RemarkType>
          <ed:RemarkValue>Vessel ETD - 19/03/21\nTARE WEIGHT - 2880 KGS</ed:RemarkValue>
        </ed:Remark>   </ed:Remarks>   <ed:Products>
        <ed:Product>
          <ed:ProductItem>1</ed:ProductItem>
          <ed:Exhausted>true</ed:Exhausted>
          <ed:Origin>AO</ed:Origin>
          <ed:Description>BONELESS BEEF RUMP CAP</ed:Description>
          <ed:CommonName>Bovine</ed:CommonName>
          <ed:EligibilityCountries>
            <ed:EligibilityCountryID>US</ed:EligibilityCountryID>
          </ed:EligibilityCountries>
          <ed:IntendedUse>consumption</ed:IntendedUse>
          <ed:GrossWeight unitCode="KGM">296.4</ed:GrossWeight>
          <ed:NetWeight unitCode="KGM">271.6</ed:NetWeight>
          <ed:Remarks>
            <ed:Remark>
              <ed:RemarkType>Product Statement</ed:RemarkType>
              <ed:RemarkValue>Item No. 81625\nLabel Approval 2659305 &amp; 91060858</ed:RemarkValue>
            </ed:Remark>
          </ed:Remarks>
          <ed:Classifications>
            <ed:Classification>
              <ed:ClassificationType>Temperature</ed:ClassificationType>
              <ed:ClassificationValue>chilled</ed:ClassificationValue>
            </ed:Classification>
            <ed:Classification>
              <ed:ClassificationType>New Zealand Harmonised System Code</ed:ClassificationType>
              <ed:ClassificationValue>020130</ed:ClassificationValue>
            </ed:Classification>
            <ed:Classification>
              <ed:ClassificationType>Halal Product</ed:ClassificationType>
              <ed:ClassificationValue>1</ed:ClassificationValue>
            </ed:Classification>
          </ed:Classifications>
          <ed:Containers>
            <ed:Container>
              <ed:ID>CGMU3099999</ed:ID>
              <ed:Seals>
                <ed:ID>NZMPIXXXXX</ed:ID>
              </ed:Seals>
            </ed:Container>
          </ed:Containers>
          <ed:Packaging>
            <ed:Package>
              <ed:Quantity>29</ed:Quantity>
              <ed:Type>CT</ed:Type>
              <ed:Level>1</ed:Level>
              <ed:ShippingMarks>
                <ed:Name>MABC\n26913</ed:Name>
              </ed:ShippingMarks>
            </ed:Package>
          </ed:Packaging>
          <ed:Processes>
            <ed:Process>
              <ed:ProcessTypeCode>SLT</ed:ProcessTypeCode>
              <ed:StartDate>2021-03-01</ed:StartDate>
              <ed:EndDate>2021-03-01</ed:EndDate>
              <ed:DateOverride>false</ed:DateOverride>
              <ed:Premise>
                <ed:ID>MEABC</ed:ID>
              </ed:Premise>
            </ed:Process>
            <ed:Process>
              <ed:ProcessTypeCode>PRO</ed:ProcessTypeCode>
              <ed:StartDate>2021-03-02</ed:StartDate>
              <ed:EndDate>2021-03-02</ed:EndDate>
              <ed:DateOverride>false</ed:DateOverride>
              <ed:Premise>
                <ed:ID>MEABC</ed:ID>
              </ed:Premise>
            </ed:Process>
            <ed:Process>
              <ed:ProcessTypeCode>CST</ed:ProcessTypeCode>
              <ed:StartDate>2021-03-02</ed:StartDate>
              <ed:EndDate>2021-03-10</ed:EndDate>
              <ed:DateOverride>false</ed:DateOverride>
              <ed:Premise>
                <ed:ID>MEABC</ed:ID>
              </ed:Premise>
            </ed:Process>
          </ed:Processes>
        </ed:Product> 
</ed:Products>  
     </ed:Certificate>

This is what I have tried so far - Figured if I can access one element, I can slowly work on the rest

  if OBJECT_ID('tempdb..#XmlImportTest') is not null
    drop table #XmlImportTest
      
    CREATE TABLE #XmlImportTest(
    xmlFileName VARCHAR(300) NOT NULL,
    xml_data XML NOT NULL
    );
    
    DECLARE @xmlFileName VARCHAR(200) ='K:\Upload\CSNXML\WaybillXml.xml'
    EXEC('INSERT INTO #XmlImportTest(xmlFileName, xml_data)
    
    SELECT ''' + @xmlFileName + ''', xmlData
    FROM(
    SELECT *
    FROM OPENROWSET (BULK ''' + @xmlFileName + ''', SINGLE_BLOB) AS XMLDATA
    ) AS FileImport (XMLDATA)
    ')
    
    DECLARE @XML AS XML, @hDoc AS INT, @SQL NVARCHAR (MAX)
    
    SELECT @xml = (SELECT xml_data from #XmlImportTest)
    EXEC sp_xml_preparedocument @hDoc OUTPUT, @XML
        
        DECLARE @XML AS XML, @hDoc AS INT, @SQL NVARCHAR (MAX)
        
        SELECT @xml = (SELECT xml_data from #XmlImportTest)
    EXEC sp_xml_preparedocument @hDoc OUTPUT, @XML
    ;WITH XMLNAMESPACES ('http://sancrt.mpi.govt.nz/ecert/2013/ed-multiple-submission-schema.xsd' AS ed)
    
    SELECT 
    
    p.value(N'@ProductItem',N'nvarchar(10)') AS ProductItem
          
    FROM 
    @xml.nodes('/Certificate')
      
    AS A(p)
    CROSS APPLY a.p.nodes(N'Products/Product') AS B(m);

I don't get any results returned.

I get the same result using OPENROWSET as well.

Can someone please tell me how I can access this data element.

Upvotes: 0

Views: 56

Answers (1)

AlwaysLearning
AlwaysLearning

Reputation: 8809

You seem to be getting confused about XML Namespaces. The example document defines two namespace URIs:

  1. http://sancrt.mpi.govt.nz/ecert/2013/ed-multiple-submission-schema.xsd, which has no prefix so is considered to be the "default" namespace of the document.
  2. http://sancrt.mpi.govt.nz/ecert/2013/ed-submission-schema.xsd, which uses the ed namespace prefix that, by eyeballing it, seems to be used on every element in the document so might as well be the default namespace.

Your simplest example is trying to extract the value of the /Certificate/Products/Product/ProductItem elements which could be done as simply as:

with xmlnamespaces (
  default 'http://sancrt.mpi.govt.nz/ecert/2013/ed-submission-schema.xsd'
)
select productItem.value(N'text()[1]', N'int') as ProductItem
from @xml.nodes('/Certificate/Products/Product/ProductItem') as p(productItem);

Expanding on this to select a few more values, you can see the @ being used here to access the unitCode attribute of an element:

with xmlnamespaces (
  default 'http://sancrt.mpi.govt.nz/ecert/2013/ed-submission-schema.xsd'
)
select
  product.value(N'(ProductItem/text())[1]', N'int') as ProductItem,
  product.value(N'(Exhausted/text())[1]', N'bit') as Exhausted,
  product.value(N'(Origin/text())[1]', N'nvarchar(2)') as Origin,
  product.value(N'(GrossWeight/text())[1]', N'decimal(19,1)') as GrossWeight,
  product.value(N'(GrossWeight/@unitCode)[1]', N'nvarchar(3)') as GrossWeightUnitCode
from @xml.nodes('/Certificate/Products/Product') as p(product);

It should be clear from the above two queries that the namespace prefixes used XPath query don't have to be the same as the ones used in the XML document - it's the namespace URIs themselves that matter. The prefixes in the document are used to link the elements (and sometimes attributes) to their namespace URIs, the prefixes used in XPath can be completely different so long as they reference the correct namespace URIs. e.g. this query returns the same result as the second example above, despite their being no submission prefixes in the source XML:

with xmlnamespaces (
  'http://sancrt.mpi.govt.nz/ecert/2013/ed-multiple-submission-schema.xsd' as multiple,
  'http://sancrt.mpi.govt.nz/ecert/2013/ed-submission-schema.xsd' as submission
)
select
  product.value(N'(submission:ProductItem/text())[1]', N'int') as ProductItem,
  product.value(N'(submission:Exhausted/text())[1]', N'bit') as Exhausted,
  product.value(N'(submission:Origin/text())[1]', N'nvarchar(2)') as Origin,
  product.value(N'(submission:GrossWeight/text())[1]', N'decimal(19,1)') as GrossWeight,
  product.value(N'(submission:GrossWeight/@unitCode)[1]', N'nvarchar(3)') as GrossWeightUnitCode,
product.value(N'(submission:Remarks/submission:Remark/submission:RemarkType/text())[1]', N'nvarchar(50)') as item_remark
from @xml.nodes('/submission:Certificate/submission:Products/submission:Product') as p(product);

Upvotes: 2

Related Questions