.NET 8.0中xs:token元素未自动规范化空白字符?
.NET 8中xs:token类型元素验证后未自动去除前后空白的问题
我使用C#和.NET 8.0.6开发,定义了一个XSD,其中root元素的类型为xs:token。按照xs:token的定义,它应该自动去除内容前后的空白,但验证包含前后空白的实例文档后,这些空白却被保留了下来,不符合预期。
XSD内容
<?xml version='1.0'?> <xs:schema targetNamespace = "http://example.org/scratch" xmlns = "http://example.org/scratch" xmlns:xs = "http://www.w3.org/2001/XMLSchema"> <xs:element name="root" type="xs:token"/> </xs:schema>
实例文档内容
<?xml version='1.0'?> <pre:root xmlns:pre="http://example.org/scratch"> abc </pre:root>
执行步骤
- 将XSD读取为
System.Xml.Schema.XmlSchema对象 - 将该架构添加到
System.Xml.Schema.SchemaSet并编译 - 创建XmlReader时使用以下配置:
var xmlReaderSettings = new XmlReaderSettings { CheckCharacters = true, DtdProcessing = DtdProcessing.Prohibit, Schemas = xmlSchemaSet, ValidationType = ValidationType.Schema, };
- 使用
System.Xml.XmlDocument.Load(xmlReader)加载实例文档
加载后的结果
加载后的文档内容如下:
<?xml version="1.0"?> <pre:root xmlns:pre="http://example.org/scratch"> abc </pre:root>
XmlDocument.DocumentElement的相关属性:
InnerXml: " abc "NamespaceURI: "http://example.org/scratch"SchemaInfo.SchemaType.TypeCode: Token
解决方法
问题在于XmlDocument仅负责验证内容是否符合XSD约束,不会主动根据类型规则修改文档内容,因此不会自动执行xs:token的空白规范化操作。以下是几种实现空白处理的方案:
方案1:通过XmlReader直接获取规范化值
XmlReader在读取符合xs:token类型的元素内容时,会自动处理空白,直接读取即可得到规范化后的值:
using (var reader = XmlReader.Create("实例文档路径", xmlReaderSettings)) { while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element && reader.LocalName == "root") { string normalizedValue = reader.ReadElementContentAsString(); // normalizedValue 结果为"abc",前后空白已去除 break; } } }
方案2:加载文档后手动规范化
如果需要保留文档结构,可在加载后通过SchemaInfo判断元素类型,手动执行空白处理:
XmlDocument doc = new XmlDocument(); doc.Load(reader); XmlElement root = doc.DocumentElement; if (root.SchemaInfo.SchemaType is XmlSchemaSimpleType simpleType && simpleType.TypeCode == XmlTypeCode.Token) { string normalizedValue = XmlConvert.ToString(XmlConvert.ToToken(root.InnerText)); root.InnerText = normalizedValue; // 处理后root的InnerText为"abc" }
方案3:使用XmlSerializer反序列化
若可以将XML反序列化为实体类,XmlSerializer会自动处理xs:token类型的空白:
[XmlRoot(Namespace = "http://example.org/scratch")] public class Root { [XmlText] public string Value { get; set; } } var serializer = new XmlSerializer(typeof(Root)); using (var reader = XmlReader.Create("实例文档路径", xmlReaderSettings)) { Root rootObj = (Root)serializer.Deserialize(reader); // rootObj.Value 结果为"abc" }
内容的提问来源于stack exchange,提问作者voidp
相关产品推荐
相关产品推荐

