XML 解析 - SQL 服务器 Table 中未知行和列的 "Illegal XML Character" 的错误消息

XML Parsing - Error Message for "Illegal XML Character" for Unknown Row & Column in SQL Server Table

我正在尝试解析 SQL 服务器上数据 table 中的 xml 列,将内容转换为我尝试创建的数据框中的新列。我一直收到错误

Msg 9420, Level 16, State 1, Line 1
XML parsing: line 20, character 2005, illegal xml character

而且我不知道如何解决这个问题。此非法字符不存在于每一行的 xml 列中。

我的 SQL 代码能够解析 570,000 行,然后遇到包含非法字符的行并停止 运行。我的 WHERE 子句假设解析并提取 1,200,000 行。因此,代码能够在退出前成功解析不到一半的所需行。 xml 列存储为 varchar,因此我确实需要 CAST 到 xml 才能解析内容。

此 SQL 代码确实有效。它处理原始数据,其中包含生产数据和虚假测试数据的混合。我只能访问生产 table,正是因为这个 table 我遇到了错误。仅在将数据传输到生产环境时数据一定发生了变化 table.

我尝试在帖子中搜索可以提供帮助的内容,但我找不到任何内容。我不知道如何在我正在处理的 1.2M 记录中找到错误,或者是哪个已解析的列导致了问题。有没有办法让解析算法跳过有问题的行并继续解析剩余的记录?

我的代码是:

SELECT [Id]
      ,[EventDateTime]
      ,[TenantId]
      ,[EventType]
      ,[EventXml]
      ,[InsertDateTime]
      ,[AppInstanceId]
      ,[TokenCorrelationId]
      ,[AuditCorrelationId]
      ,[AuditId]
      ,CAST([EventXml] as XML).value('/PrescriptionEvent [1]/DateTimeStamp[1]','NVARCHAR(max)') AS xml_DateTimeStamp 
      ,UPPER(CAST([EventXml] as XML).value('/PrescriptionEvent[1]/AuditCorrelationId[1]','NVARCHAR(max)')) AS xml_AuditCorrelationId
      ,UPPER(CAST([EventXml] as XML).value('/PrescriptionEvent[1]/TokenCorrelationId[1]','NVARCHAR(max)')) AS xml_TokenCorrelationId
      ,UPPER(CAST([EventXml] as XML).value('/PrescriptionEvent[1]/ActingUserId[1]/Value[1]','NVARCHAR(max)')) AS xml_ActingUserId
      ,UPPER(CAST([EventXml] as XML).value('/PrescriptionEvent[1]/ActingUserId[1]/LegacyId[1]','NVARCHAR(max)')) AS xml_ActingUserId_LegacyId
      ,UPPER(CAST([EventXml] as XML).value('/PrescriptionEvent[1]/TenantId[1]/Value[1]','NVARCHAR(max)')) AS xml_TenantId
      ,UPPER(CAST([EventXml] as XML).value('/PrescriptionEvent[1]/TenantId[1]/LegacyId[1]','NVARCHAR(max)')) AS xml_TenantId_LegacyId
      ,UPPER(CAST([EventXml] as XML).value('/PrescriptionEvent[1]/AppInstanceId[1]/Value[1]','NVARCHAR(max)')) AS xml_AppInstanceId
      ,UPPER(CAST([EventXml] as XML).value('/PrescriptionEvent[1]/AppInstanceId[1]/LegacyId[1]','NVARCHAR(max)')) AS xml_AppInstanceId_LegacyId
      ,UPPER(CAST([EventXml] as XML).value('/PrescriptionEvent[1]/ActionType[1]','NVARCHAR(max)')) AS xml_ActionType
      ,UPPER(CAST([EventXml] as XML).value('/PrescriptionEvent[1]/Outcome[1]','NVARCHAR(max)')) AS xml_Outcome
      ,UPPER(CAST([EventXml] as XML).value('/PrescriptionEvent[1]/OutcomeReason[1]','NVARCHAR(max)')) AS xml_OutcomeReason
      ,UPPER(CAST([EventXml] as XML).value('/PrescriptionEvent[1]/RxSigningWorkflowActivity[1]','NVARCHAR(max)')) AS xml_RxSigningWorkflowActivity
      ,UPPER(CAST([EventXml] as XML).value('/PrescriptionEvent[1]/Waypoint[1]','NVARCHAR(max)')) AS xml_Waypoint
      ,UPPER(CAST([EventXml] as XML).value('/PrescriptionEvent[1]/PrescriptionReferenceId[1]','NVARCHAR(max)')) AS xml_PrescriptionReferenceId
  FROM [EpcsAuditDB].[dbo].[EpcsAuditEventData]
  WHERE [EventType] = 4 AND [EventDateTime] >= '2020-03-24'

xml的例子(这个没有非法字符;不知道如何找到包含非法字符的那个):

<?xml version="1.0" encoding="utf-8"?>  <PrescriptionEvent xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">    <DateTimeStamp>2020-03-24T19:54:33.0169582Z</DateTimeStamp>    <Outcome>true</Outcome>    <OutcomeReason />    <AuditCorrelationId>3a4fb1cd-c39c-4e84-bfc4-dee98b29be2e</AuditCorrelationId>    <TokenCorrelationId>d80bbd23-2e1d-44b3-9452-972b54f35cc9</TokenCorrelationId>    <ActingUserId>      <Value>91f78a00-ce26-4088-88eb-11x5565910d7</Value>    </ActingUserId>    <TenantId>      <Value>00000000-0000-0000-0000-000000000000</Value>      <LegacyId>10051804</LegacyId>    </TenantId>    <AppInstanceId>      <Value>00000000-0000-0000-0000-000000000000</Value>      <LegacyId>Hospital</LegacyId>    </AppInstanceId>    <PrescriptionReferenceId>ecf5fd42-096e-ea11-a852-005056a9ea50</PrescriptionReferenceId>    <AdditionalPrescriptionReferenceId />    <ActionType>Received</ActionType>    <RxSigningWorkflowActivity>RxArchive</RxSigningWorkflowActivity>    <Waypoint>SMS</Waypoint>  </PrescriptionEvent>

错误不是由您的 XML 中的列引起的,而是因为 XML 无效。它被演员扔到 XML.

根据您的 sql 服务器版本,您应该能够通过以下方式找到错误行:

select EventXml 
from [EpcsAuditDB].[dbo].[EpcsAuditEventData]
where try_cast([EventXml] as XML) is null

您可以使用TRY_CONVERT查看无效xml内容的数据。下面的 POC 代码会有帮助。

DECLARE @tableWithxml table(id int, xmlcontent varchar(500))

INSERT INTO @tableWithxml
values (1,'<x> 1</x>'), (2,'<x 1</x>')

SELECT id, xmlcontent
from
(SELECT id, xmlcontent, try_convert(xml,xmlcontent) as conversionsucceed
from @tableWithxml) as t
where conversionsucceed is null -- failed conversion
+----+------------+
| id | xmlcontent |
+----+------------+
|  2 | <x 1</x>   |
+----+------------+