SQL Server 2016 从 XML 中提取信息

SQL Server 2016 extract info from XML

我浏览过关于同一主题的各种帖子,但我似乎无法访问我的 XML 文件中的数据元素。

这是我的 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>

这是我迄今为止尝试过的方法 - 想通了如果我可以访问一个元素,我可以慢慢处理其余部分

  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);

我没有返回任何结果。

我也使用 OPENROWSET 得到相同的结果。

谁能告诉我如何访问这个数据元素。

您似乎对 XML 命名空间感到困惑。示例文档定义了两个名称空间 URI:

  1. http://sancrt.mpi.govt.nz/ecert/2013/ed-multiple-submission-schema.xsd,它没有前缀,因此被认为是文档的“默认”命名空间。
  2. http://sancrt.mpi.govt.nz/ecert/2013/ed-submission-schema.xsd,它使用了 ed 命名空间前缀,通过观察它,似乎在文档中的每个元素上都使用了它,所以也可能是默认命名空间。

您最简单的示例是尝试提取 /Certificate/Products/Product/ProductItem 元素的值,可以像这样简单地完成:

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);

将其扩展到 select 几个值,您可以看到此处使用 @ 来访问元素的 unitCode 属性:

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);

从以上两个查询中应该清楚,使用 XPath 查询的命名空间前缀不必与 XML 文档中使用的相同 - 重要的是命名空间 URI 本身。文档中的前缀用于 link 元素(有时是属性)到它们的名称空间 URI,XPath 中使用的前缀可以完全不同,只要它们引用正确的名称空间 URI。例如此查询 returns 与上面第二个示例的结果相同,尽管它们在源 XML:

中没有 submission 前缀
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);