C#用XmlSchemaInference生成XSD时如何替换xs:sequence允许任意元素顺序
解决方案
你可以在生成XmlSchemaSet后、写入XSD文件前,直接修改内存中的Schema结构,将符合要求的xs:sequence替换为xs:all,这种方式比修改生成后的文本文件更可靠,不会出现格式匹配错误。
实现思路
xs:all在XSD 1.0标准下要求内部所有元素的maxOccurs只能为1,刚好可以匹配你提到的「从XML样本识别可多次出现的元素」的需求:只要xs:sequence下存在子元素maxOccurs>1就保留原sequence,否则替换为all- 遍历所有Schema的复杂类型定义,批量替换符合要求的粒子即可
代码实现
在你原有代码的schemaSet = schema.InferSchema(reader);之后,遍历写入文件之前,加入以下处理逻辑:
// 遍历所有生成的Schema foreach (XmlSchema schema in schemaSet.Schemas()) { // 遍历所有复杂类型定义 foreach (XmlSchemaObject item in schema.Items) { if (item is XmlSchemaElement element && element.SchemaType is XmlSchemaComplexType complexType) { // 检查是否是sequence粒子 if (complexType.Particle is XmlSchemaSequence sequence) { bool canConvertToAll = true; // 检查所有子元素的maxOccurs是否都为1 foreach (XmlSchemaObject subItem in sequence.Items) { if (subItem is XmlSchemaElement subElement) { if (subElement.MaxOccurs > 1) { canConvertToAll = false; break; } } // 如果有其他嵌套粒子(比如choice、嵌套sequence)也不转换 else { canConvertToAll = false; break; } } if (canConvertToAll) { // 新建xs:all粒子 XmlSchemaAll all = new XmlSchemaAll(); // 复制原sequence的配置和子元素 all.MinOccurs = sequence.MinOccurs; all.MaxOccurs = sequence.MaxOccurs; foreach (var subItem in sequence.Items) { all.Items.Add(subItem); } // 替换原sequence complexType.Particle = all; } } } } }
注意事项
- 如果你需要支持XSD 1.1标准下
xs:all允许maxOccurs>1的特性,可以去掉子元素MaxOccurs的校验逻辑,不过.NET内置的XmlSchema类默认遵循XSD 1.0规范,强行设置可能导致后续Schema校验报错 - 嵌套的sequence结构默认不会被转换,如果你需要处理嵌套场景,可以递归遍历粒子结构即可
内容的提问来源于stack exchange,提问作者Martin Přívozník
相关产品推荐
相关产品推荐

