无法使用外部应用解析 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_preparedocument
和 sp_xml_removedocument
只是为了与过时的 SQL Server 2000 向后兼容。它们的使用已减少到极少数边缘情况。
我必须注释掉以下标签 <!--<IntervalReadings>-->
以使您的 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的主要内容,如果未能解决你的问题,请参考以下文章
无法在 JSF 应用程序中解析文档 faces-config.xml
error LNK2019: 无法解析的外部符号;fatal error LNK1120: 1 个无法解析的外部命令; 可能存在的问题