Jyina
Jyina

Reputation: 2892

How to retrieve minoccurs value from XSD in C#?

I am trying to figure out the correct cast type for the "Parent" property of an object of type XmlSchemaSimpleType. The below code is always returning "" as the "parent" variable is validated to null. Can anyone please help how to retrieve minOccurs from the parent of a simpleType ? Thank you!

private string GetMinOccurs(XmlSchemaSimpleType xsdSimpleType)
{
    var parent = xsdSimpleType.Parent as XmlSchemaElement;

    if (parent == null) return "";

    return parent.MinOccurs.ToString();
}

An example of my XSD is:

<xsd:complexType name="New_Type">
  <xsd:sequence>
    <xsd:element name="Amount" type="Amount_Type"  minOccurs="1" maxOccurs="1" />
    <xsd:element name="Name" type="Name_Type"  minOccurs="1" maxOccurs="1" />
  </xsd:sequence>
</xsd:complexType>

<xsd:simpleType name="Amount_Type">
  <xsd:annotation>
    <xsd:documentation>Amount</xsd:documentation>
  </xsd:annotation>
  <xsd:restriction base="xsd:string">
    <xsd:maxLength value="12" />
  </xsd:restriction>
</xsd:simpleType>

Upvotes: 3

Views: 1171

Answers (1)

psubsee2003
psubsee2003

Reputation: 8741

Like I said in the comment of your previous question. the Parent property of an XmlSchemaSimpleType does not work like you think. It looks like you are hoping it will return the <element> that has a type of the XmlSchemaSimpleType you are specifying.

But consider this situation:

<xsd:complexType name="New_Type">
  <xsd:sequence>
    <xsd:element name="Amount" type="Amount_Type"  minOccurs="1" maxOccurs="1" />
    <xsd:element name="OtherAmount" type="Amount_Type"  minOccurs="10" maxOccurs="15" />
    <xsd:element name="Name" type="Name_Type"  minOccurs="1" maxOccurs="1" />
  </xsd:sequence>
</xsd:complexType>

<xsd:simpleType name="Amount_Type">
  <xsd:annotation>
    <xsd:documentation>Amount</xsd:documentation>
  </xsd:annotation>
  <xsd:restriction base="xsd:string">
    <xsd:maxLength value="12" />
  </xsd:restriction>
</xsd:simpleType>

Which would it return as there are 2 different elements with the same type? As you can see from this example, a type can be used multiple times throughout an XSD and each occurance can have a different MinOccurs value. If you want to get the MinOccurs, you need to find the exact <element> you want, even if the type is used just once. But to do that you need to know where it is in the XSD.

This blog is a few years old, but I think helps with the point. You basically have to find the complex type using XmlSchemaSet.GlobalTypes[], then you need to look through the Particle property. In your case, there will be a single XmlSchemaSequence object in there (you'll probably need to cast). Then you need to look through the items property to find your Amount element. From there (after another cast), you can get MinOccurs.

If you don't know exactly what you are looking for, all of the collections in the XmlSchemaObject properties do have GetEnumerator methods, so you can use foreach to help scan everything. None are generic though so you need to do a lot of casting, but this is basically what you have to do:

foreach (DictionaryEntry item in set.GlobalTypes)
{
    // set.GlobalTypes.GetEnumerator returns an object, so you need to cast to DictionaryEntry 
    // DictionaryEntry.Key and DictionaryEntry.Value are objects too so you need to cast again
    // Particle is an XmlSchemaObject, so you need to cast to an XmlSchemaSequence

    var seq = (XmlSchemaSequence)((XmlSchemaComplexType)item.Value).Particle;

    // XmlSchemaSequence.Items also returns an XmlSchemaObject so you need to cast again to XmlSchemaElement.

    foreach (XmlSchemaElement i in seq.Items)
    {
        if (i.SchemaTypeName == new XmlQualifiedName("Amount_Type"))
        {
            Console.WriteLine(i.MinOccursString);
        }
    }
}

But this is just an example to show how to get where you want to go. You need to do some type checking before each of the casts in case it fails. For example, var seq = (XmlSchemaSequence)((XmlSchemaComplexType)item.Value).Particle; will throw an exception after it gets to the second type in your XSD since it is not a complex type, it is a simple type.

A LINQ solution might be easier if you know exactly what you want:

var xDoc = XDocument.Load("your XSD path");
var ns = XNamespace.Get(@"http://www.w3.org/2001/XMLSchema");

var minOccurs = from element in xDoc.Descendants()
                where (String)element.Attribute("type") == "Amount_Type"
                select (String)element.Attribute("minOccurs");

This method at least lets you scan the document quickly for any type that matches your Amount_Type and grabs the minOccurs (or returns null of there is no minOccurs attribute).

Upvotes: 1

Related Questions