【问题标题】:XML Namespace confusion in SQLSQL 中的 XML 命名空间混淆
【发布时间】:2021-05-13 00:37:45
【问题描述】:

我有一个需要修改的 XML 文件。

我可以在 SQL 中很好地加载文件,但是当我尝试读取一些节点时,我什么也没有返回……也没有错误。我做错了什么?

我的 XML 开头是这样的:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<batch_request xmlns="http://sancrt.mpi.govt.nz/ecert/2013/batch-submission-schema.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://sancrt.mpi.govt.nz/ecert/2013/batch-submission-schema.xsd batchsubmission- schema.xsd">
  <raise_eligibility_document>
    <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:Identifiers>
        <ed:CertificateID>26920</ed:CertificateID>
        <ed:TemplateID>ED1</ed:TemplateID>
      </ed:Identifiers>
      <ed:DepartureDate>2021-03-10</ed:DepartureDate>
      <ed:Parties>
        <ed:ConsignorID>XX345</ed:ConsignorID>
        <ed:ConsigneeID>FLIGHT1</ed:ConsigneeID>
      </ed:Parties>

这是我加载和读取此文件的 SQL 语句以及我返回节点的尝试。

Declare  @xmlFile VARCHAR(30) = 'TESTING'

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 @xmlpath varchar(200) = 'Location of file'

declare @xmlFileName varchar(200) = @xmlpath+@xmlFile+'.xml' 

--– dynamic sql is just so we can use @xmlFileName variable in OPENROWSET

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)

--select @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
   
         header.value(N'(submission:Identifiers/submission:CertificateID/text())[1]', N'nvarchar(20)') as ecert_number
 
        from @xml.nodes('/submission:Certificate') as ci(header)

这不返回任何内容。

我也试过这个:

from   

    @xml.nodes('/submission:batch_request/submission:raise_eligibility_document/submission:Certificate') as ci(header)

我也尝试将以下内容用于提交名称空间

;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 ,
  'http://sancrt.mpi.govt.nz/ecert/2013/batch-submission-schema.xsd' as submission
)

我仍然一无所有..请问我哪里出了问题?

【问题讨论】:

    标签: sql-server xml sql-server-2016 xml-namespaces


    【解决方案1】:

    这是一个完整的重现如何正确地做到这一点。

    提点:

    • 只有两个名称空间与提供的 XML 摘录相关。之一 它们是默认命名空间,因此不需要它的前缀。第二 命名空间需要“ed”前缀。
    • 现在在两个位置都有适当的 XPath 表达式,即 .nodes().value() XQuery 方法。

    SQL

    DECLARE @xml XML =
    N'<batch_request xmlns="http://sancrt.mpi.govt.nz/ecert/2013/batch-submission-schema.xsd"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="http://sancrt.mpi.govt.nz/ecert/2013/batch-submission-schema.xsd batchsubmission- schema.xsd">
        <raise_eligibility_document>
            <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:Identifiers>
                    <ed:CertificateID>26920</ed:CertificateID>
                    <ed:TemplateID>ED1</ed:TemplateID>
                </ed:Identifiers>
                <ed:DepartureDate>2021-03-10</ed:DepartureDate>
                <ed:Parties>
                    <ed:ConsignorID>XX345</ed:ConsignorID>
                    <ed:ConsigneeID>FLIGHT1</ed:ConsigneeID>
                </ed:Parties>
            </ed:Certificate>
        </raise_eligibility_document>
    </batch_request>';
    
    WITH XMLNAMESPACES (DEFAULT 'http://sancrt.mpi.govt.nz/ecert/2013/batch-submission-schema.xsd'
        , 'http://sancrt.mpi.govt.nz/ecert/2013/ed-submission-schema.xsd' AS ed)
    SELECT c.value('(ed:Identifiers/ed:CertificateID/text())[1]', 'VARCHAR(30)') AS CertificateID
        , c.value('(ed:Identifiers/ed:TemplateID/text())[1]', 'VARCHAR(30)') AS TemplateID
        , c.value('(ed:DepartureDate/text())[1]', 'DATE') AS DepartureDate
        , c.value('(ed:Parties/ed:ConsignorID/text())[1]', 'VARCHAR(30)') AS ConsignorID
        , c.value('(ed:Parties/ed:ConsigneeID/text())[1]', 'VARCHAR(30)') AS ConsigneeID
    FROM @xml.nodes('/batch_request/raise_eligibility_document/ed:Certificate') AS t(c);
    

    输出

    +---------------+------------+---------------+-------------+-------------+
    | CertificateID | TemplateID | DepartureDate | ConsignorID | ConsigneeID |
    +---------------+------------+---------------+-------------+-------------+
    |         26920 | ED1        | 2021-03-10    | XX345       | FLIGHT1     |
    +---------------+------------+---------------+-------------+-------------+
    

    【讨论】:

    • 对您更正内容的一些解释会改善您的答案。
    【解决方案2】:

    Certificate 不是文档的根节点,因此@xml.nodes('/submission:Certificate') 似乎不正确。请尝试以下方法(注意//):

    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
      header.value(N'(submission:Identifiers/submission:CertificateID/text())[1]', N'nvarchar(20)') as ecert_number
    from @xml.nodes('//submission:Certificate') as ci(header);
    

    【讨论】:

      猜你喜欢
      • 2012-09-06
      • 2012-03-29
      • 2014-04-14
      • 2014-01-15
      • 2022-06-17
      • 1970-01-01
      • 1970-01-01
      • 2023-01-30
      • 2023-03-14
      相关资源
      最近更新 更多