【问题标题】:XML Schemas -- List allowed attributes/tags at position in XMLXML Schemas -- 在 XML 的位置列出允许的属性/标签
【发布时间】:2011-10-13 00:35:24
【问题描述】:

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

<tagset>
  <a></a>
  <b><!-- CURSOR IS HERE --></b>
</tagset>

【问题讨论】:

    标签: c# xml schema


    【解决方案1】:

    有办法,但是 Xml Schema 规范很复杂,所以需要一些努力和几百行代码。

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

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

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

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

    以下不完整的代码sn-p包含了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);
                            }
                        }
                    }
                }
            }
        }
    

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

        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;
        }
    

    并处理一个简单的类型:

        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
                }
            }
        }
    

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

    当 XML 无效时,XML 编辑器仍应提供自动完成帮助,这为问题增加了额外的维度,因为如果验证上下文有限且架构设计更像“俄罗斯娃娃”而不是“意大利腊肠切片”。

    总结

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

    【讨论】:

    • 哦,伙计...我应该知道我已经为这个项目注册了大量的工作。无论哪种方式,GetExpectedParticles 正是我一直在寻找的那种东西,即使它不是微不足道的。非常感谢。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-01
      • 2015-05-30
      • 1970-01-01
      相关资源
      最近更新 更多