XML Schema - 在XML中列出允许的属性/标签

Mik*_*ark 5 c# xml schema

有没有办法在XML中的某个点查询XmlSchemaXmlSchemaSet列出可用的标签/属性?所以说我的光标位于<b>和之间,</b>并且我的模式只允许在<c/>那里使用一个元素,我可以用C#内置的任何东西来解决这个问题吗?

<tagset>
  <a></a>
  <b><!-- CURSOR IS HERE --></b>
</tagset>
Run Code Online (Sandbox Code Playgroud)

pgf*_*aro 5

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

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

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

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

最好分开分别获取预期元素和属性的代码.

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

      public static List<XmlSchemaObject> XsdExpectedElements(XmlSchemaSet schemaSet,
                    List<NodeDescriptor> nodePath)
      {
        List<XmlSchemaObject> elementNames = new List<XmlSchemaObject>();          

        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<XmlSchemaElement> 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);
                        }
                    }
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

    private List<string> ExpectedEnumValues(XmlSchemaObject xsso)
    {
        XmlSchemaSimpleType xst = null;
        XmlSchemaComplexType xsCt = null;
        List<string> values = new List<string>();
        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;
    }
Run Code Online (Sandbox Code Playgroud)

并处理一个简单的类型:

    private static void ProcessXmlSimpleType(XmlSchemaSimpleType xst, List<string> 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
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

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

摘要

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