无法使用外部应用解析 XML

Posted

技术标签:

【中文标题】无法使用外部应用解析 XML【英文标题】:Can't parse XML with outer apply 【发布时间】:2021-12-10 11:53:07 【问题描述】:

我在表中有一个 XML 列,我试图将值从平面表结构中解析出来。

我正在尝试在此处输入 XML,但 *** 将其设置为代码,当我尝试将其格式化为代码时,它仍然不接受它。

我什至无法从“标题”级别获取数据。

<RequestMessage xmlns="http://iec.ch/TC57/2011/schema/message" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Message.xsd">
  <Header>
    <Verb>created</Verb>
    <Noun>MeterReadings</Noun>
    <Timestamp>2021-03-08T00:57:18+01:00</Timestamp>
    <Source>Ipsum Lorum</Source>
    <AsyncReplyFlag>true</AsyncReplyFlag>
    <AckRequired>true</AckRequired>
    <MessageID>Ipsum Lorum</MessageID>
    <CorrelationID />
  </Header>
  <Payload>
    <MeterReadings xmlns:MeterReadings="http://iec.ch/TC57/2011/MeterReadings#" xmlns="http://iec.ch/TC57/2011/MeterReadings#">
      <MeterReading>
        <IntervalBlocks>
          <IntervalReadings>
            <timeStamp>2021-03-07T01:00:00+01:00</timeStamp>
            <value>480.196</value>
            <ReadingQualities>
              <ReadingQualityType ref="3.0.0" />
            </ReadingQualities>
          </IntervalReadings>
          <IntervalReadings>
            <ReadingType ref="11.0.7.3.1.2.12.1.1.0.0.0.0.101.0.3.72.0" />
          </IntervalReadings>
        </IntervalBlocks>
        <Meter>
          <mRID>0000000000000</mRID>
          <status>
            <remark>Ipsum Lorum</remark>
            <value>ESP</value>
          </status>
        </Meter>
        <UsagePoint>
          <mRID>73599900000000</mRID>
        </UsagePoint>
      </MeterReading>
    </MeterReadings>
  </Payload>
</RequestMessage>

我无法解析它,我尝试使用其他线程的示例。我试图不使用 OPENXML 解决方案,因为需要 DECLARE 并执行内置过程以定期从内存中清除 XML。我正在尝试使用 OUTER APPLY 解决方案。 就像 How to parse XML data in SQL server table 或 Query XML with nested nodes on Cross Apply 中的 Shugos 解决方案。

它不起作用。

时间戳列返回null。

select 
t.file_created_time
,c.value('(Timestamp)[1]','varchar(max)') as timestamp
from load.t t
OUTER APPLY t.xml_data.nodes('RequestMessage/Header') as m(c)

【问题讨论】:

正如@marc_s 已经提到的,XML 格式不正确。 提问时,您需要提供minimal reproducible example: (1) DDL 和样本数据填充,即 CREATE 表和 INSERT T-SQL 语句。 (2) 你需要做什么,即逻辑和你的代码尝试在 T-SQL 中实现它。 (3) 期望的输出,基于上述#1 中的样本数据。 (4) 您的 SQL Server 版本 (SELECT @@version;)。 @YitzhakKhabinsky 感谢您提供有关我应该在帖子中包含的内容的信息。我认为 XML 文本和我正在运行的 sql 代码就足够了,但我知道有些人可能使用的是非常旧版本的 sql server,所以我会认为将来会这样。 现在我了解命名空间的问题是我搜索了一下并发现例如 ***.com/questions/22818591/… 和评论 vittore 似乎暗示不需要使用 WITH 和命名空间声明的问题。相反,可以只接受任何命名空间。但是我还没有让它工作,但下一步很有趣。我有动力尝试在没有 CTE 的情况下工作。 【参考方案1】:

请尝试以下解决方案。

从 SQL Server 2005 开始,最好使用基于 w3c 标准的 XQuery 语言,同时处理 XML 数据类型。

保留 Microsoft 专有的 OPENXML 及其伙伴 sp_xml_preparedocumentsp_xml_removedocument 只是为了与过时的 SQL Server 2000 向后兼容。它们的使用已减少到极少数边缘情况。

我必须注释掉以下标签 &lt;!--&lt;IntervalReadings&gt;--&gt; 以使您的 XML 格式正确。

XML Header 片段有一个默认命名空间:

xmlns="http://iec.ch/TC57/2011/schema/message"

XML Payload 片段有自己的两个额外命名空间:

xmlns:MeterReadings="http://iec.ch/TC57/2011/MeterReadings#" xmlns="http://iec.ch/TC57/2011/MeterReadings#"

应考虑命名空间。

在下面查看。

SQL

DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, xml_data XML);
INSERT INTO @tbl (xml_data) VALUES
(N'<RequestMessage xmlns="http://iec.ch/TC57/2011/schema/message"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:noNamespaceSchemaLocation="Message.xsd">
    <Header>
        <Verb>created</Verb>
        <Noun>MeterReadings</Noun>
        <Timestamp>2021-03-08T00:57:18+01:00</Timestamp>
        <Source>Ipsum Lorum</Source>
        <AsyncReplyFlag>true</AsyncReplyFlag>
        <AckRequired>true</AckRequired>
        <MessageID>Ipsum Lorum</MessageID>
        <CorrelationID/>
    </Header>
    <Payload>
        <MeterReadings xmlns:MeterReadings="http://iec.ch/TC57/2011/MeterReadings#"
                       xmlns="http://iec.ch/TC57/2011/MeterReadings#">
            <MeterReading>
                <IntervalBlocks>
                    <IntervalReadings>
                        <timeStamp>2021-03-07T01:00:00+01:00</timeStamp>
                        <value>480.196</value>
                        <ReadingQualities>
                            <ReadingQualityType ref="3.0.0"/>
                        </ReadingQualities>
                    </IntervalReadings>
                    <!--<IntervalReadings>-->
                    <ReadingType ref="11.0.7.3.1.2.12.1.1.0.0.0.0.101.0.3.72.0"/>
                </IntervalBlocks>
                <Meter>
                    <mRID>0000000000000</mRID>
                    <status>
                        <remark>Ipsum Lorum</remark>
                        <value>ESP</value>
                    </status>
                </Meter>
                <UsagePoint>
                    <mRID>73599900000000</mRID>
                </UsagePoint>
            </MeterReading>
        </MeterReadings>
    </Payload>
</RequestMessage>');
-- DDL and sample data population, end

WITH XMLNAMESPACES(DEFAULT 'http://iec.ch/TC57/2011/schema/message')
SELECT id
    , c.value('(Noun/text())[1]','VARCHAR(30)') AS Noun
    , c.value('(Timestamp/text())[1]','DATETIMEOFFSET(0)') AS [timestamp]
FROM @tbl
    CROSS APPLY xml_data.nodes('/RequestMessage/Header') AS t(c);

输出

+----+---------------+----------------------------+
| id |     Noun      |         timestamp          |
+----+---------------+----------------------------+
|  1 | MeterReadings | 2021-03-08 00:57:18 +01:00 |
+----+---------------+----------------------------+

【讨论】:

非常感谢。你的解决方案奏效了。【参考方案2】:

您需要在 XQuery 的 XML 文档中尊重并包含​​ XML 命名空间

<RequestMessage xmlns="http://iec.ch/TC57/2011/schema/message"
                **********************************************

试试这样的:

WITH XMLNAMESPACES(DEFAULT N'http://iec.ch/TC57/2011/schema/message')
SELECT
    t.id,
    c.value('(Timestamp)[1]','varchar(max)') as timestamp
FROM
    load.t t
CROSS APPLY
    t.xml_data.nodes('RequestMessage/Header') AS m(c)

另外,当我尝试在我的 SQL Server 上运行它时,我收到一个错误,显示的 XML 格式不正确.....

更新:

如果您还需要访问 Payload 部分中的位 - 您还需要尊重那里的 那个 XML 命名空间:

<MeterReadings xmlns:MeterReadings="http://iec.ch/TC57/2011/MeterReadings#"
               xmlns="http://iec.ch/TC57/2011/MeterReadings#">
               ***********************************************

试试这个:

WITH XMLNAMESPACES(N'http://iec.ch/TC57/2011/schema/message' as hdr,
                   N'http://iec.ch/TC57/2011/MeterReadings#' as mr)
SELECT
    t.id,
    c.value('(hdr:Timestamp)[1]', 'varchar(50)') AS timestamp,
    col.value('(mr:MeterReading/mr:IntervalBlocks/mr:IntervalReadings/mr:timeStamp)[1]', 'varchar(50)') AS MeterReadingsTimestamp
FROM
    load.t t
CROSS APPLY
    t.xml_data.nodes('/hdr:RequestMessage/hdr:Header') AS m(c)
CROSS APPLY
    t.xml_data.nodes('/hdr:RequestMessage/hdr:Payload/mr:MeterReadings') AS mr(col)

【讨论】:

非常感谢。你的解决方案奏效了。 为什么它适用于 Header 但是当我为 Payload 运行它(更改命名空间)时它不起作用? WITH XMLNAMESPACES(DEFAULT N'http://iec.ch/TC57/2011/MeterReadings#') SELECT t.file_name,c.value('(/UsagePoint/mRID)[1]','varchar(max)') as timestamp FROM load.t t OUTER APPLY t.xml_data.nodes('RequestMessage/Payload') AS m(c) Yitzak 提到 Payload 有 2 个命名空间。这可能是问题吗?是否需要以某种方式将两个命名空间都加载到 WITH cte? @MattiasW:再一次 - 你有一个 XML 命名空间,但你没有将它集成到你的 XQuery 中!用如何执行此操作的示例更新了我的回复。 现在我看到了你是如何使用命名空间的。它似乎绑定到别名,因此它将“hdr:”绑定到“iec.ch/TC57/2011/schema/message”,将“mr:”绑定到iec.ch/TC57/2011/MeterReadings#。 @MattiasW: 是的 - 确切地说 - 命名空间实际上是“iec.ch/TC57/2011/MeterReadings#”部分 - 它的 前缀 用于在 XPath 表达式中引用它跨度>

以上是关于无法使用外部应用解析 XML的主要内容,如果未能解决你的问题,请参考以下文章

error LNK2019: 无法解析的外部符号

无法在 JSF 应用程序中解析文档 faces-config.xml

VC中使用openGL链接显示 无法解析的外部符号

VC中使用openGL链接显示 无法解析的外部符号

error LNK2019: 无法解析的外部符号;fatal error LNK1120: 1 个无法解析的外部命令; 可能存在的问题

error LNK2019: 无法解析的外部符号