如何正确处理 UTF-8 XML 中的?
How do I properly handle  in UTF-8 XML?
我在表示 
时遇到了一些问题,这是一个有效的 UTF-16 结构,而且显然在 Windows 文件名中有效,在 XML 中用于在 [=36= 中使用] 服务器 XML (2012).
以此为例:
DECLARE @Xml xml;
SET @Xml = N'<?xml version="1.0"?><FileName>풜〣</FileName>'
-- Result: XML parsing: line 1, character 41, illegal xml character
然而,这是合法的 Unicode("Unicode Noncharacter" ''):http://www.fileformat.info/info/unicode/char/ffff/index.htm
所以,我尝试了这个:
DECLARE @Xml xml;
SET @Xml = N'<?xml version="1.0" encoding="utf-16"?><FileName>풜〣</FileName>'
-- Result: XML parsing: line 1, character 59, illegal xml character
那么 - 我应该如何在 XML 中准确地表示此文件名?我不能只删除字符,它们确实是 Get-ChildItem 报告的 
个字符,我需要保留此文件的句柄。
我可以通过将 
替换为 ï¿¿
来使 XML 解析工作,ï¿¿
根据 this link 是 \uFFFF
的 UTF-8 表示然后我尝试将此 XML 插入到 nvarchar
列,我需要它作为文件名的正确表示。
DECLARE @Xml xml;
SET @Xml = N'<?xml version="1.0"?><FileName>풜〣ï¿¿ï¿¿</FileName>'
SELECT F.Item.value('.', 'nvarchar(2000)') FROM @Xml.nodes('//FileName') as F(Item)
-- Returns 풜〣ï¿¿ï¿¿ (not correct)
XML 文档中允许的字符集由 XML 规范的 production 2 定义。它不包括 U+FFFF(它被 Unicode 定义为非字符,并且在 XML 开发时不允许使用 Unicode 进行信息交换)。
这意味着您不能在 XML 文档中按字面意思表示 U+FFFF,也不能使用 XML 数字字符引用。您当然可以发明自己的转义机制,或使用 URI 转义之类的方法来对数据中的字符进行编码;在将数据插入允许 U+FFFF 的应用程序之前,您当然必须对您的表示进行转义。
我想知道为什么 Windows 文件名中允许非字符。

(即十进制 65535)不是合法字符,即使根据 [=59= 问题中提供的 link ]. link 表明它是非法的、非字符的,并且不能以任何方式表示(根据他们的测试页)。
另外,根据Unicode.org:
Noncharacters
These codes are intended for process-internal uses.
FFFE <not a character>
• may be used to detect byte order by contrast with FEFF
→ FEFF = zero width no-break space
FFFF <not a character>
而且,根据 W3C,valid characters 的列表是:
#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
/* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */
为了将其转换为 XML(至少在 SQL 服务器 XML 数据类型方面),您需要首先替换任何出现的 
和 
使用自定义转义序列,例如 \uFFFE;
和 \uFFFF;
分别。然后,当转换回 NVARCHAR 时,您只需分别将 \uFFFE;
替换为 NCHAR(65534)
并将 \uFFFF;
替换为 NCHAR(65535)
。
或,您可以对值进行 Base64 编码(在应用程序代码端相当容易)并在输出时解码。如果您需要在数据库端访问它,您可以创建自己的 SQLCLR 函数来进行 Base64 编码和解码,或者只获取 SQL# 库的免费版本(我是) 其中包括 Convert_ToBase64
和 Convert_FromBase64
并且可以按如下方式使用:
DECLARE @Encoded NVARCHAR(200),
@Decoded NVARCHAR(200);
SET @Encoded =
SQL#.Convert_ToBase64(CONVERT(VARBINARY(200), N'f' + NCHAR(65535) + N'g'), 'None');
SELECT CONVERT(XML, N'<test>' + @Encoded + N'</test>');
SET @Decoded = SQL#.Convert_FromBase64(@Encoded);
SELECT @Encoded AS [Encoded],
@Decoded AS [Decoded],
DATALENGTH(@Decoded) AS [NumBytes], -- 6 bytes = 3 characters (most of the time)
UNICODE(SUBSTRING(@Decoded, 2, 1)) AS [TaDa!] -- get value of middle character
Returns:
<test>ZgD//2cA</test>
然后:
Encoded Decoded NumBytes TaDa!
ZgD//2cA fg 6 65535
它似乎不应该用作文件名的一部分(我知道这不是你做的),或者它可能确实是一个有效字符,但被 Get-ChildItem
错误地读取了。
I will need to retain a handle to this file.
是否可以在将 names/info 导入 SQL 服务器之前重命名文件以删除无效字符?只是一个想法。
仅供参考,您不能通过 xml 声明更改编码,至少不是那么容易:
我在表示 
时遇到了一些问题,这是一个有效的 UTF-16 结构,而且显然在 Windows 文件名中有效,在 XML 中用于在 [=36= 中使用] 服务器 XML (2012).
以此为例:
DECLARE @Xml xml;
SET @Xml = N'<?xml version="1.0"?><FileName>풜〣</FileName>'
-- Result: XML parsing: line 1, character 41, illegal xml character
然而,这是合法的 Unicode("Unicode Noncharacter" ''):http://www.fileformat.info/info/unicode/char/ffff/index.htm
所以,我尝试了这个:
DECLARE @Xml xml;
SET @Xml = N'<?xml version="1.0" encoding="utf-16"?><FileName>풜〣</FileName>'
-- Result: XML parsing: line 1, character 59, illegal xml character
那么 - 我应该如何在 XML 中准确地表示此文件名?我不能只删除字符,它们确实是 Get-ChildItem 报告的 
个字符,我需要保留此文件的句柄。
我可以通过将 
替换为 ï¿¿
来使 XML 解析工作,ï¿¿
根据 this link 是 \uFFFF
的 UTF-8 表示然后我尝试将此 XML 插入到 nvarchar
列,我需要它作为文件名的正确表示。
DECLARE @Xml xml;
SET @Xml = N'<?xml version="1.0"?><FileName>풜〣ï¿¿ï¿¿</FileName>'
SELECT F.Item.value('.', 'nvarchar(2000)') FROM @Xml.nodes('//FileName') as F(Item)
-- Returns 풜〣ï¿¿ï¿¿ (not correct)
XML 文档中允许的字符集由 XML 规范的 production 2 定义。它不包括 U+FFFF(它被 Unicode 定义为非字符,并且在 XML 开发时不允许使用 Unicode 进行信息交换)。
这意味着您不能在 XML 文档中按字面意思表示 U+FFFF,也不能使用 XML 数字字符引用。您当然可以发明自己的转义机制,或使用 URI 转义之类的方法来对数据中的字符进行编码;在将数据插入允许 U+FFFF 的应用程序之前,您当然必须对您的表示进行转义。
我想知道为什么 Windows 文件名中允许非字符。

(即十进制 65535)不是合法字符,即使根据 [=59= 问题中提供的 link ]. link 表明它是非法的、非字符的,并且不能以任何方式表示(根据他们的测试页)。
另外,根据Unicode.org:
Noncharacters
These codes are intended for process-internal uses.FFFE <not a character>
• may be used to detect byte order by contrast with FEFF
→ FEFF = zero width no-break spaceFFFF <not a character>
而且,根据 W3C,valid characters 的列表是:
#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
/* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */
为了将其转换为 XML(至少在 SQL 服务器 XML 数据类型方面),您需要首先替换任何出现的 
和 
使用自定义转义序列,例如 \uFFFE;
和 \uFFFF;
分别。然后,当转换回 NVARCHAR 时,您只需分别将 \uFFFE;
替换为 NCHAR(65534)
并将 \uFFFF;
替换为 NCHAR(65535)
。
或,您可以对值进行 Base64 编码(在应用程序代码端相当容易)并在输出时解码。如果您需要在数据库端访问它,您可以创建自己的 SQLCLR 函数来进行 Base64 编码和解码,或者只获取 SQL# 库的免费版本(我是) 其中包括 Convert_ToBase64
和 Convert_FromBase64
并且可以按如下方式使用:
DECLARE @Encoded NVARCHAR(200),
@Decoded NVARCHAR(200);
SET @Encoded =
SQL#.Convert_ToBase64(CONVERT(VARBINARY(200), N'f' + NCHAR(65535) + N'g'), 'None');
SELECT CONVERT(XML, N'<test>' + @Encoded + N'</test>');
SET @Decoded = SQL#.Convert_FromBase64(@Encoded);
SELECT @Encoded AS [Encoded],
@Decoded AS [Decoded],
DATALENGTH(@Decoded) AS [NumBytes], -- 6 bytes = 3 characters (most of the time)
UNICODE(SUBSTRING(@Decoded, 2, 1)) AS [TaDa!] -- get value of middle character
Returns:
<test>ZgD//2cA</test>
然后:
Encoded Decoded NumBytes TaDa!
ZgD//2cA fg 6 65535
它似乎不应该用作文件名的一部分(我知道这不是你做的),或者它可能确实是一个有效字符,但被 Get-ChildItem
错误地读取了。
I will need to retain a handle to this file.
是否可以在将 names/info 导入 SQL 服务器之前重命名文件以删除无效字符?只是一个想法。
仅供参考,您不能通过 xml 声明更改编码,至少不是那么容易: