XML Schema – 在XML中的位置列出允许的属性/标签

有没有办法在XML中的某个点查询XmlSchemaXmlSchemaSet以获取可用标记/属性的列表? 所以说我的光标在 ,我的模式只允许在那里使用元素,我可以用C#内置的任何东西来解决这个问题吗?

     

有一种方法,但Xml Schema规范很复杂,因此需要花费一些精力和几百行代码。

.NET XmlSchemaValidator类的GetExpectedParticles方法是解决方案的关键部分。 这使用作为参数传递的XmlSchemaSet来返回一组XmlSchemaObject实例。

在调用此方法之前,您需要构建一个指向光标位置的节点路径,该路径必须包含祖先元素及其前面的兄弟节点以及当前嵌套级别的前一个兄弟节点。 此节点路径用于设置架构validation程序的上下文。

调用GetExpectedParticles后,您需要处理粒子。 例如,检查每个预期粒子是否是替换组的成员,并检查预期粒子是否是枚举的受限简单类型。

最好将分别取出预期元素和属性的代码分开。

以下不完整的代码段包含GetExpectedParticles方法调用,这仅适用于元素标记内容,而不是属性:

  public static List XsdExpectedElements(XmlSchemaSet schemaSet, List nodePath) { List elementNames = new List(); NameTable nt = new NameTable(); XmlNamespaceManager manager = new XmlNamespaceManager(nt); XmlSchemaValidator validator = new XmlSchemaValidator(nt, schemaSet, manager, XmlSchemaValidationFlags.None); // event handler sets validationErrorFound local field validator.ValidationEventHandler += new ValidationEventHandler(validator_ValidationEventHandler); validator.Initialize(); XmlSchemaInfo xsInfo = new XmlSchemaInfo(); int i = 0; foreach (nodeDescriptor nameUri in nodePath) { validator.ValidateElement(nameUri.LocalName, nameUri.NamespaceUri, xsInfo); if ((i >= siblingPosition && siblingPosition > -1) || nameUri.Closed) { validator.SkipToEndElement(null); } else { validator.ValidateEndOfAttributes(null); } i++; } XmlSchemaParticle[] parts = validator.GetExpectedParticles(); if (parts.Length == 0) { bool hasElements = true; bool elementClosed = nodePath[nodePath.Count - 1].Closed; if (elementClosed) // we're outside the element tags { hasElements = true; } else if (xsInfo.SchemaType is XmlSchemaSimpleType) { hasElements = false; } else { XmlSchemaComplexType xsCt = xsInfo.SchemaType as XmlSchemaComplexType; XmlSchemaContentType xsContent = (XmlSchemaContentType)xsCt.ContentType; if (xsContent == XmlSchemaContentType.TextOnly) { hasElements = false; } } if (!hasElements) { expectedType = XmlEditor.expectedListType.elementValue; if (xsInfo.SchemaElement != null) { elementNames.Add(xsInfo.SchemaElement); } } return elementNames; } foreach (XmlSchemaObject xso in parts) { if (xso is XmlSchemaElement) { XmlSchemaElement xse = (XmlSchemaElement)xso; if (subGroupList.ContainsKey(xse.QualifiedName)) { List xses = subGroupList[xse.QualifiedName]; foreach (XmlSchemaElement xseInstance in xses) { elementNames.Add(xseInstance); } } else { elementNames.Add(xse); } } else if (xso is XmlSchemaAny) { XmlSchemaAny xsa = (XmlSchemaAny)xso; foreach (XmlSchema xs in schemaSet.Schemas()) { if (xs.TargetNamespace == xsa.Namespace) { foreach (XmlSchemaElement xseAny in xs.Elements) { elementNames.Add(xseAny); } } } } } } 

以下(不完整的)代码段显示了如何从粒子中获取预期的枚举值:

  private List ExpectedEnumValues(XmlSchemaObject xsso) { XmlSchemaSimpleType xst = null; XmlSchemaComplexType xsCt = null; List values = new List(); if (xsso == null) { return values; } if (xsso is XmlSchemaAttribute) { XmlSchemaAttribute xsa = (XmlSchemaAttribute)xsso; xst = xsa.AttributeSchemaType; } else { XmlSchemaElement xse = (XmlSchemaElement)xsso; XmlSchemaType gxst = xse.ElementSchemaType; if (gxst is XmlSchemaSimpleType) { xst = (XmlSchemaSimpleType)gxst; } else if (gxst is XmlSchemaComplexType) { xsCt = (XmlSchemaComplexType)gxst; } else { return values; } } if(xst != null) { if (xst.TypeCode == XmlTypeCode.Boolean) { values.Add("true"); values.Add("false"); } else { ProcessXmlSimpleType(xst, values); } } else if (xsCt != null) { XmlSchemaContentType xsContent = (XmlSchemaContentType) xsCt.ContentType; XmlSchemaContentModel xsModel = (XmlSchemaContentModel)xsCt.ContentModel; if (xsModel is XmlSchemaSimpleContent) { XmlSchemaSimpleContent xsSC = (XmlSchemaSimpleContent)xsModel; XmlSchemaContent xsRE = xsSC.Content; if (xsRE != null) { if (xsRE is XmlSchemaSimpleContentRestriction) { XmlSchemaSimpleContentRestriction xsCCR = (XmlSchemaSimpleContentRestriction)xsRE; foreach (XmlSchemaObject xso in xsCCR.Facets) { if (xso is XmlSchemaEnumerationFacet) { XmlSchemaEnumerationFacet xsef = (XmlSchemaEnumerationFacet)xso; values.Add(xsef.Value); } } } } } else { XmlSchemaComplexContent xsCC = (XmlSchemaComplexContent)xsModel; XmlSchemaContent xsRE = xsCC.Content; if (xsRE != null) { if (xsRE is XmlSchemaComplexContentRestriction) { XmlSchemaComplexContentRestriction xsR = (XmlSchemaComplexContentRestriction)xsRE; } else if (xsRE is XmlSchemaComplexContentExtension) { XmlSchemaComplexContentExtension xsE = (XmlSchemaComplexContentExtension)xsRE; } } } } return values; } 

并处理一个简单的类型:

  private static void ProcessXmlSimpleType(XmlSchemaSimpleType xst, List values) { if (xst == null) { return; } XmlSchemaSimpleTypeContent xsstc = xst.Content; if (xsstc is XmlSchemaSimpleTypeRestriction) { XmlSchemaSimpleTypeRestriction xsr = (XmlSchemaSimpleTypeRestriction)xsstc; XmlSchemaObjectCollection xsoc = xsr.Facets; XmlSchemaSimpleType bastTypeOfRestiction = xsr.BaseType; foreach (XmlSchemaObject xso in xsoc) { if (xso is XmlSchemaEnumerationFacet) { XmlSchemaEnumerationFacet xsef = (XmlSchemaEnumerationFacet)xso; values.Add(xsef.Value); } } } else if (xsstc is XmlSchemaSimpleTypeList) { XmlSchemaSimpleTypeList xsstL = (XmlSchemaSimpleTypeList)xsstc; XmlSchemaSimpleType xstL = xsstL.BaseItemType; ProcessXmlSimpleType(xstL, values); // recursive } else if (xsstc is XmlSchemaSimpleTypeUnion) { XmlSchemaSimpleTypeUnion xstU = (XmlSchemaSimpleTypeUnion)xsstc; XmlSchemaSimpleType[] xsstArray = xstU.BaseMemberTypes; foreach (XmlSchemaSimpleType xsstA in xsstArray) { ProcessXmlSimpleType(xsstA, values); // recursive } } } 

上面的代码片段可能解决了所需内容的20%,但希望能让您对将要处理的内容有所了解。 .NET提供了一组非常强大的类来分析模式对象模型,但是您需要详细了解XML模式规范才能获得可用的结果。

当XML无效时,XML编辑器仍然应该提供自动完成帮助,这为问题增加了额外的维度,因为如果validation上下文有限并且架构设计比“萨拉米切片”更“俄式娃娃”,则可能存在歧义。

摘要

使用.NET获取XML实例中给定上下文的预期XML模式粒子列表是可能的,但相对复杂。 鉴于此,首先检查现有.NET XML编辑器中的库是否提供了所需的function是值得的。

对于LGPL下的工作实现,请查看SharpDevelops XmlEditor部分。 您可以在一个dll中获取xml的代码完成,即AddIns / DisplayBindings目录中的XmlEditor.dll。