Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
277 views
in Technique[技术] by (71.8m points)

c# - XmlSchema inferred from an XML file - how to iterate through all the elements in the XSD?

I have an XML file and I'm inferring its XSD schema in run-time, using the XmlSchemaInference class.

Sample file:

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

It does work - it infers the schema nicely:

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

The question is:

How can I iterate (recursively?) through all the elements from this schema? How are they stored by the XmlSchemaSet class? I need to present them to the user so they can do some mapping.

I am retrieving an XmlSchema from XmlSchemaSet.Schemas property, and then what? XmlSchema.Elements only contains one item (products), and I can't find any way to look up what its subelements are.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Okay! No answer and not much interest - I figured it out on my own.

I used code from this MSDN article I googled up: Traversing XML Schemas

And I based my recursive solution on it.

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

The output is:

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)

I leave to you to judge how friendly this API is, especially given how scarce is the MSDN documentation on these particular classes. Any comments or insights are appreciated.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...