简体   繁体   中英

How to parse xs:annotation from the xs:choice using the System.Xml.Schema

I'm trying to add the annotation element inside the xs:choice. According to the xs:choice syntax, this could be possible. I could not find the sample of choice with annotation inside BTW. My current version of xsd file contains an element:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="http://www.es.de/es3/flex/simple"
             elementFormDefault="qualified"
             xmlns="http://www.es.de/es3/flex/simple"
             xmlns:mstns="http://tempuri.org/XMLSchema.xsd"
             xmlns:xs="http://www.w3.org/2001/XMLSchema"
             xmlns:flex="http://www.es.de/es3/flex/flexBase">

    <xs:import namespace="http://www.es.de/es3/flex/flexBase" />

    <xs:element name="ESS3754">
        <xs:complexType>
            <xs:choice>
                <xs:annotation>
                    <xs:appinfo>
                        <flex:ControlHeadline>Headline_VVVVV</flex:ControlHeadline>
                        <flex:helpText>HelpText_VVVVV</flex:helpText>
                    </xs:appinfo>
                </xs:annotation>
                <xs:element name="String1" type="xs:string" minOccurs="1" maxOccurs="1"/>
            </xs:choice>
        </xs:complexType>
    </xs:element>

</xs:schema>

However, while parsing the xsd file, the Annotation of the object System.Xml.Schema.XmlSchemaChoice is always null.

The code part:

public List<FSBaseItem> Parse( XmlTextReader xsdReader )
        {
            try
            {
                // prepare schema set for schema validation and raw template xsd "enrichment"
                XmlSchemaSet schemaSet = new XmlSchemaSet();
                schemaSet.ValidationEventHandler += ValidationCallbackOne;

                // include base schema
                XmlSchema baseXsd = FlexXmlSchemaReader.ReadBase();
                schemaSet.Add( baseXsd );

                // The Read method will throw errors encountered on parsing the schema
                XmlSchema xsd = XmlSchema.Read( xsdReader, ValidationCallbackOne );
                schemaSet.Add( xsd );

                // The Compile method will throw errors encountered on compiling the schema
                schemaSet.Compile();

                // create root
                FSElement rootElement = new FSElement( this.GetNewId() );
                // traverse body
                this.TraverseSOM( xsd, rootElement );
                // validate
                this.ValidateFSItems( rootElement.Items );
                // init lists containers with minimum elements
                InitEmptyFEListItems( rootElement );                

                return rootElement.Items;
            }
            finally
            {
                xsdReader.Close();
            }
        }

Already in the beginig the choice element annotation is null :( . Could somebody give some working sample or add some hints? Any help would be appreciated.

Annotations certainly can be put inside xs:choice. Look at the following xsd taken from Inline Annotated Schema

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" 
  xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" 
  jaxb:version="1.0" jaxb:extensionBindingPrefixes="xjc">
    <xs:annotation>
        <xs:appinfo>
            <jaxb:globalBindings>
                <xjc:superClass name="com.syh.Shape"/>
            </jaxb:globalBindings>
        </xs:appinfo>
    </xs:annotation>
    <xs:element name="Widgets">
        <xs:complexType>
            <xs:choice minOccurs="0" maxOccurs="unbounded">
                <xs:annotation>
                    <xs:appinfo>
                        <jaxb:property name="Shapes"/>
                    </xs:appinfo>
                </xs:annotation>
                <xs:element name="Rectangle" type="Rectangle"/>
                <xs:element name="Square" type="Square"/>
                <xs:element name="Circle" type="Circle"/>
            </xs:choice>
         </xs:complexType>
    </xs:element>
    <xs:complexType name="Rectangle">
        <xs:sequence>
            <xs:element name="Width" type="xs:integer"/>
            <xs:element name="Height" type="xs:integer"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="Square">
        <xs:sequence>
            <xs:element name="Length" type="xs:integer"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="Circle">
        <xs:sequence>
            <xs:element name="Radius" type="xs:integer"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

Adapting similar strategy to your xsd yields something like the following:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="http://www.es.de/es3/flex/simple"
             elementFormDefault="qualified"
             xmlns="http://www.es.de/es3/flex/simple"
             xmlns:mstns="http://tempuri.org/XMLSchema.xsd"
             xmlns:xs="http://www.w3.org/2001/XMLSchema"
             xmlns:flex="http://www.es.de/es3/flex/flexBase">

  <xs:import namespace="http://www.es.de/es3/flex/flexBase" />

  <xs:element name="ESS3754">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:annotation>
          <xs:appinfo>
            <flex:ControlHeadline>Headline_VVVVV</flex:ControlHeadline>
            <flex:helpText>HelpText_VVVVV</flex:helpText>
          </xs:appinfo>
        </xs:annotation>
        <xs:element name="String1" type="xs:string" minOccurs="1" maxOccurs="10"/>
        <xs:element name="NewlyAdded" type="Coordinate" minOccurs="1" maxOccurs="10"/>
      </xs:choice>
    </xs:complexType>    
  </xs:element>
  <xs:complexType name="Coordinate">
  <xs:sequence>
    <xs:element name="LocationX" type="xs:integer"/>
    <xs:element name="LocationY" type="xs:integer"/>
    <xs:element name="LocationZ" type="xs:integer"/>
  </xs:sequence>
</xs:complexType>    

</xs:schema>

and the xsd is perfectly valid and looks like the following in Visual Studio [XSD] Desginer:

在此输入图像描述

Update 1

I agree on the fact that debugger shows item annotation as null [I could not find it either but I should] and it is quite frustrating. I reconstructed the document using the code and you can annotate your element using the following workaround: Consider the following XSD which does not have any XmlSchemaChoice and is saved as stack-problem2.xsd

<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="http://www.es.de/es3/flex/simple"
             elementFormDefault="qualified"
             xmlns="http://www.es.de/es3/flex/simple"
             xmlns:mstns="http://tempuri.org/XMLSchema.xsd"
             xmlns:xs="http://www.w3.org/2001/XMLSchema"
             xmlns:flex="http://www.es.de/es3/flex/flexBase">

  <xs:import namespace="http://www.es.de/es3/flex/flexBase" />




  <xs:complexType name="Coordinate">
    <xs:sequence>
      <xs:element name="LocationX" type="xs:integer"/>
      <xs:element name="LocationY" type="xs:integer"/>
      <xs:element name="LocationZ" type="xs:integer"/>
    </xs:sequence>
  </xs:complexType>  
</xs:schema>

Now you can load this into memory and add annotations programmatically to the XmlSchemaChoice element:

public void Parse()
{
    try
    {
        XmlTextReader reader2 = new XmlTextReader(@"stack-problem2.xsd");
        XmlSchema myschema2 = XmlSchema.Read(reader2, ValidationCallback);


        var simpleAnotation = new XmlSchemaAnnotation();
        simpleAnotation.Id = "Lost Anotation";

        // <xs:complexType name="ESS3754">
        XmlSchemaComplexType complexType = new XmlSchemaComplexType();
        myschema2.Items.Add(complexType);
        complexType.Name = "ESS3754";

        // <xs:choice minOccurs="1" maxOccurs="1">
        XmlSchemaChoice choice = new XmlSchemaChoice();
        complexType.Particle = choice;
        choice.MinOccurs = 1;
        choice.MaxOccurs = 1;

        XmlSchemaElement elementSelected = new XmlSchemaElement();
        choice.Items.Add(elementSelected);
        elementSelected.Name = "String1";

        AnnonateMyComplexType(choice); 

        FileStream file = new FileStream(@"satck-solution.xsd", FileMode.Create, FileAccess.ReadWrite);
        XmlTextWriter xwriter = new XmlTextWriter(file, new UTF8Encoding());
        xwriter.Formatting = Formatting.Indented;
        myschema2.Write(xwriter);
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
    }
}

public static void AnnonateMyComplexType(XmlSchemaChoice xmlSchemaComplexType)
{

    XmlSchemaAnnotation myCustomAnnotation = new XmlSchemaAnnotation();
    xmlSchemaComplexType.Annotation = myCustomAnnotation;

    // <xs:documentation>State Name</xs:documentation>
    XmlSchemaDocumentation schemaDocumentation = new XmlSchemaDocumentation();
    myCustomAnnotation.Items.Add(schemaDocumentation);
    schemaDocumentation.Markup = TextToNodeArray("Headline_VVVVV");

    // <xs:appInfo>Application Information</xs:appInfo>
    XmlSchemaAppInfo appInfo = new XmlSchemaAppInfo();
    myCustomAnnotation.Items.Add(appInfo);
    appInfo.Markup = TextToNodeArray("Headline_VVVVV");

}

static void ValidationCallback(object sender, ValidationEventArgs args)
{
    if (args.Severity == XmlSeverityType.Warning)
        Console.Write("WARNING: ");
    else if (args.Severity == XmlSeverityType.Error)
        Console.Write("ERROR: ");

    Console.WriteLine(args.Message);
}

Running above will return the following XSD file:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns="http://www.es.de/es3/flex/simple" xmlns:flex="http://www.es.de/es3/flex/flexBase" xmlns:mstns="http://tempuri.org/XMLSchema.xsd" elementFormDefault="qualified" targetNamespace="http://www.es.de/es3/flex/simple" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:import namespace="http://www.es.de/es3/flex/flexBase" />
  <xs:complexType name="Coordinate">
    <xs:sequence>
      <xs:element name="LocationX" type="xs:integer" />
      <xs:element name="LocationY" type="xs:integer" />
      <xs:element name="LocationZ" type="xs:integer" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="ESS3754">
    <xs:choice minOccurs="1" maxOccurs="1">
      <xs:annotation>
        <xs:documentation>Headline_VVVVV</xs:documentation>
        <xs:appinfo>Headline_VVVVV</xs:appinfo>
      </xs:annotation>
      <xs:element name="String1" />
    </xs:choice>
  </xs:complexType>
</xs:schema>

So to answer your first question: Yes, Annotation can be definitely put inside XmlSchemaChoice elements (Both through code and directly) [Not necessarily outside xmlSchemaChoice as the top element based on your experiment] and to address your second problem: [I had similar experience as of yours! It shows the annotation as null although it is not]

For anyone else running into this issue, I have found by reflecting the classes of the System.Xml.Schema namespace that, upon compiling a schemaset, the annotations of elements are copied to their children.

So Vytas999 should be able (as I have been able) to find his missing annotation by inspecting the XmlSchemaParticle objects in the XmlSchemaChoice.Items property.

I ran into the same problem - I needed to process an XSD provided by external entity and the Annotation of XmlSchemaChoice was always null.

Elaborating on @Adrian's answers the code I successfully use is below. In my case I traverse the schema from the root down, when I hit XmlSchemaSequence I itereate over its Items collection:

var index = 0;
foreach (var childObject in sequence.Items)
{
    ExtractElement(childObject, index);
    ++index ;
}

When childObject is of type XmlSchemaChoice (assuming it is in variable xmlSchemaChoice , then instead of

// DOES NOT WORK - always null
var choiceAnnotation = xmlSchemaChoice.Annotation

I access the Annotation like this:

((xmlSchemaChoice.Parent as XmlSchemaSequence)?.Items[index] as XmlSchemaChoice)?.Annotation

Would you expect the same result? Well, it is not..

This code is just sample snippet describing accessing the Annotation via Parent's Items, it is NOT general purpose code and might need some adaptation to your exact case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM