【问题标题】:XmlSchema inferred from an XML file - how to iterate through all the elements in the XSD?从 XML 文件推断的 XmlSchema - 如何遍历 XSD 中的所有元素?
【发布时间】:2011-09-05 19:05:46
【问题描述】:

我有一个 XML 文件,我正在使用 XmlSchemaInference 类在运行时推断其 XSD 架构。

示例文件:

<products>
    <product id="1" name="t-shirt">
        <size name="medium"/>
        <size name="large"/>
        <price>
            <net>10</net>
            <gross>25</gross>
        </price>
    </product>
    <product id="2" name="computer mouse">  
        <price>
            <net>50</net>       
        </price>
    </product>
</products>

它确实有效 - 它很好地推断了架构:

<?xml version="1.0"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="products">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" name="product">
          <xs:complexType>
            <xs:sequence>
              <xs:element minOccurs="0" maxOccurs="unbounded" name="size">
                <xs:complexType>
                  <xs:attribute name="name" type="xs:string" use="required" />
                </xs:complexType>
              </xs:element>
              <xs:element name="price">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element name="net" type="xs:unsignedByte" />
                    <xs:element minOccurs="0" name="gross" type="xs:unsignedByte" />
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
            <xs:attribute name="id" type="xs:unsignedByte" use="required" />
            <xs:attribute name="name" type="xs:string" use="required" />
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

问题是:

如何迭代(递归?)通过此架构中的所有元素? XmlSchemaSet 类如何存储它们?我需要将它们呈现给用户,以便他们可以进行一些映射。

我正在从XmlSchemaSet.Schemas 属性中检索XmlSchema,然后呢? XmlSchema.Elements 只包含一项 (products),我找不到任何方法来查找它的子元素是什么。

【问题讨论】:

    标签: c# xml xsd


    【解决方案1】:

    好的!没有答案,也没有太大的兴趣——我自己想出来的。

    我使用了我在 Google 上搜索到的这篇 MSDN 文章中的代码:Traversing XML Schemas

    我的递归解决方案就是以此为基础的。

    void PrintSchema(string xmlFilePath)
    {
        var schemaSet = new XmlSchemaInference().InferSchema(XmlReader.Create(xmlFilePath));
        foreach (XmlSchemaElement element in schemaSet
            .Schemas()
            .Cast<XmlSchema>()
            .SelectMany(s => s.Elements.Values.Cast<XmlSchemaElement>()))
        {
            Debug.WriteLine(element.Name + " (element)");
            IterateOverElement(element.Name, element);
        }
    }
    
    void IterateOverElement(string root, XmlSchemaElement element)
    {
        var complexType = element.ElementSchemaType as XmlSchemaComplexType;
        if (complexType == null) 
        {
            return;
        }
        if (complexType.AttributeUses.Count > 0)
        {
            var enumerator = complexType.AttributeUses.GetEnumerator();
            while (enumerator.MoveNext())
            {
                var attribute = (XmlSchemaAttribute)enumerator.Value;
                Debug.WriteLine(root + "." + attribute.Name + " (attribute)");
            }
        }
        var sequence = complexType.ContentTypeParticle as XmlSchemaSequence;
        if (sequence == null) 
        {
            return;
        }
        foreach (XmlSchemaElement childElement in sequence.Items)
        {
            root += String.Concat(".", childElement.Name);
            Debug.WriteLine(root + " (element)");
            // recursion
            IterateOverElement(root, childElement);
        }
    }
    

    输出为:

    products (element)
    products.product (element)
    products.product.id (attribute)
    products.product.name (attribute)
    products.product.size (element)
    products.product.size.name (attribute)
    products.product.price (element)
    products.product.price.net (element)
    products.product.price.gross (element)
    

    我让你来判断这个 API 的友好程度,特别是考虑到这些特定类的 MSDN 文档是多么稀缺。感谢任何 cmets 或见解。

    【讨论】:

    • 我同意这方面的文档很糟糕。
    • 在 Core 2 中,您的 sequence.Items 包含 System.Xml.Schema.XmlSchemaAny 对象,因此会引发异常,因为它不能/不会转换为 XmlSchemaElement 类型
    • 在 Core 2 中,我为孩子们这样做:foreach (XmlSchemaParticle childElement in sequence.Items) if (childElement is XmlSchemaElement) 然后我们可以将 childElement 转换为 XmlSchemaElement 并对其进行处理
    猜你喜欢
    • 1970-01-01
    • 2014-03-11
    • 1970-01-01
    • 2021-06-17
    • 2013-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-11
    相关资源
    最近更新 更多