.NET XmlTextWriter
创建无效的xml文件。
在XML中,允许使用某些控制字符,例如“水平标签”(	
),但其他控制字符不是“垂直标签”(
)。 (见spec。)
我有一个字符串,其中包含XML中不允许的UTF-8控制字符
虽然XmlTextWriter
转义了字符,但生成的XML仍然无效。
如何确保XmlTextWriter
永远不会生成非法的XML文件?
或者,如果无法使用XmlTextWriter
执行此操作,如何从字符串中删除XML中不允许的特定控制字符?
示例代码:
using (XmlTextWriter writer =
new XmlTextWriter("test.xml", Encoding.UTF8))
{
writer.WriteStartDocument();
writer.WriteStartElement("Test");
writer.WriteValue("hello \xb world");
writer.WriteEndElement();
writer.WriteEndDocument();
}
输出:
<?xml version="1.0" encoding="utf-8"?><Test>hello  world</Test>
答案 0 :(得分:12)
此行为的文档隐藏在documentation of the WriteString method中,但听起来它适用于整个班级。
使用Create创建的XmlWriter的默认行为是throw 尝试在中写入字符值时出现ArgumentException 范围0x-0x1F(不包括空格字符0x9,0xA和0xD)。 可以通过创建XmlWriter来编写这些无效的XML字符 将CheckCharacters属性设置为false。这样做会导致 在被数字字符实体替换的字符中
�
通过�x1F
)。另外,使用new创建了一个XmlTextWriter operator将用数字字符替换无效字符 实体默认情况下。
因此您似乎最终编写了无效字符,因为您使用的是XmlTextWriter类。更好的解决方案是使用XmlWriter Class代替。
答案 1 :(得分:3)
当我遇到同样的问题时,我发现了这个问题,我最终用正则表达式来解决它:
return Regex.Replace(s, @"[\u0000-\u0008\u000B\u000C\u000E-\u001F]", "");
希望它可以帮助某人作为替代解决方案。
答案 2 :(得分:1)
内置.NET转义程序(例如SecurityElement.Escape
)也无法正确转义/删除它。
CheckCharacters
设置为false
。但是,生成的XML文件在技术上仍然是无效。 请参阅:
XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
xmlWriterSettings.Encoding = new UTF8Encoding(false);
xmlWriterSettings.CheckCharacters = false;
var sb = new StringBuilder();
var w = XmlWriter.Create(sb, xmlWriterSettings);
w.WriteStartDocument();
w.WriteStartElement("Test");
w.WriteString("hello \xb world");
w.WriteEndElement();
w.WriteEndDocument();
w.Close();
var xml = sb.ToString();
CheckCharacters
设置为true
(默认情况下)是有点过于严格,因为它只会抛出异常,对无效的XML字符更宽松的替代方法就是剥离他们:谷歌搜索产生了白名单XmlTextEncoder但是它也将删除DEL
以及根据{{{U} 00 -F + U + 0084,U + 0086-U + 009F范围内的其他人维基百科上的3}}仅在某些上下文中有效,并且RFC提到的是不鼓励但仍然有效的字符。
public static class XmlTextExtentions
{
private static readonly Dictionary<char, string> textEntities = new Dictionary<char, string> {
{ '&', "&"}, { '<', "<" }, { '>', ">" },
{ '"', """ }, { '\'', "'" }
};
public static string ToValidXmlString(this string str)
{
var stripped = str
.Select((c,i) => new
{
c1 = c,
c2 = i + 1 < str.Length ? str[i+1]: default(char),
v = XmlConvert.IsXmlChar(c),
p = i + 1 < str.Length ? XmlConvert.IsXmlSurrogatePair(str[i + 1], c) : false,
pp = i > 0 ? XmlConvert.IsXmlSurrogatePair(c, str[i - 1]) : false
})
.Aggregate("", (s, c) => {
if (c.pp)
return s;
if (textEntities.ContainsKey(c.c1))
s += textEntities[c.c1];
else if (c.v)
s += c.c1.ToString();
else if (c.p)
s += c.c1.ToString() + c.c2.ToString();
return s;
});
return stripped;
}
}
这会传递所有XmlTextEncoder测试,除了期望它将DEL
,维基百科和规范标记为有效(尽管不鼓励)字符的XmlConvert.IsXmlChar
剥离。