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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With