Deserialization to classes created from XSD does not contain all data - c#

I wanted to deserialize TCX files containing sport data into some my local/temporary object. I used XSD schema describing such format and created classes using xsd2code.
After that I was able to deserialize XML into proper object and the deserialzator didn't throw any exception. But when I started to expand behaviour of component I noticed that some fields are not properly fullfield.
The problem is about reading the tags Track. Deserialized Lap in substructure shows all data properly, but the Tracks number is displayed as 0.
Is there any way to trigger deserializer to interpret it properly? Did I miss some attribute? Why it is not reading it properly even if there was no exception.
I know, it is hard to explain and put all needed classes into comment - so I share my current status here and just write that: GetUnifiedData_WhenTrackPointsAreGivenInTcx_UnifiedTrackPointShouldRetreiveIt() is not passing and shows my problem.
<Activities>
<Activity Sport="Running">
<Id>2015-01-25T12:14:34Z</Id>
<Lap StartTime="2015-01-25T12:14:34Z">
<TotalTimeSeconds>507.0989990</TotalTimeSeconds>
<DistanceMeters>1000.0000000</DistanceMeters>
<MaximumSpeed>2.5790000</MaximumSpeed>
<Calories>95</Calories>
<AverageHeartRateBpm xsi:type="HeartRateInBeatsPerMinute_t">
<Value>155</Value>
</AverageHeartRateBpm>
<MaximumHeartRateBpm xsi:type="HeartRateInBeatsPerMinute_t">
<Value>173</Value>
</MaximumHeartRateBpm>
<Intensity>Resting</Intensity>
<TriggerMethod>Distance</TriggerMethod>
<Track>
<Trackpoint>
<Time>2015-01-25T12:14:34Z</Time>
<Position>
<LatitudeDegrees>50.8918607</LatitudeDegrees>
<LongitudeDegrees>16.7403161</LongitudeDegrees>
</Position>
<AltitudeMeters>233.1999969</AltitudeMeters>
<DistanceMeters>0.0000000</DistanceMeters>
<HeartRateBpm xsi:type="HeartRateInBeatsPerMinute_t">
<Value>88</Value>
</HeartRateBpm>
<Extensions>
<TPX xmlns="http://www.garmin.com/xmlschemas/ActivityExtension/v2" CadenceSensor="Footpod">
<Speed>0.0000000</Speed>
</TPX>
</Extensions>
</Trackpoint>
</Track>
<Track>
</Track>
<Extensions>
<FatCalories xmlns="http://www.garmin.com/xmlschemas/FatCalories/v1">
<Value>0</Value>
</FatCalories>
<LX xmlns="http://www.garmin.com/xmlschemas/ActivityExtension/v2">
<AvgSpeed>1.9720000</AvgSpeed>
</LX>
</Extensions>
</Lap>
</Activity>
</Activities>

The problem is that your data model is wrong. In the below excerpt, you will see two Track elements below the Lap element:
<?xml version="1.0" encoding="utf-16" standalone="no"?>
<TrainingCenterDatabase xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.garmin.com/xmlschemas/ActivityExtension/v2 http://www.garmin.com/xmlschemas/ActivityExtensionv2.xsd http://www.garmin.com/xmlschemas/FatCalories/v1 http://www.garmin.com/xmlschemas/fatcalorieextensionv1.xsd http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd">
<Activities>
<Activity Sport="Running">
<Id>2015-01-25T12:14:34Z</Id>
<Lap StartTime="2015-01-25T12:14:34Z">
<Track>
<Trackpoint>
<Time>2015-01-25T12:14:34Z</Time>
... etc etc
</Trackpoint>
<Trackpoint>
... etc etc
</Trackpoint>
</Track>
<Track>
<Trackpoint>
... etc etc
<Trackpoint>
</Track>
However, in your data model Track is a singleton property of Lap containing an array of TrackPoint_t entries. When XmlSerializer encounters more than one Track elements it fails to deserialize them.
Thus your data model needs to be as follows. Introduce an intermediate class Track_t:
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2")]
public class Track_t
{
public Track_t()
{
this.Track = new List<Trackpoint_t>();
}
[System.Xml.Serialization.XmlElement("TrackPoint", typeof(Trackpoint_t), IsNullable = false)]
public List<Trackpoint_t> Track { get; set; }
}
And modify ActivityLap_t as follows:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2")
]
public partial class ActivityLap_t
{
private List<Track_t> _track; // Change type to `Track_t`
public ActivityLap_t()
{
this._extensions = new Extensions_t();
this._track = new List<Track_t>(); // Change type to `Track_t`
this._maximumHeartRateBpm = new HeartRateInBeatsPerMinute_t();
this._averageHeartRateBpm = new HeartRateInBeatsPerMinute_t();
}
// Change type to `Track_t` and change attribute to `XmlElement`
[System.Xml.Serialization.XmlElement("Track", typeof(Track_t), IsNullable = false)]
public List<Track_t> Track
{
get { return this._track; }
set { this._track = value; }
}
// Remainder unchanged.
}
You will also need to modify Course_t in the same way.
The xsd does specify the existence of a type Track_t and that ActivityLap_t can contain an unbounded number of Track elements of this type, so somehow the XSD was transformed into classes incorrectly:
<xsd:complexType name="ActivityLap_t">
<xsd:sequence>
<xsd:element name="TotalTimeSeconds" type="xsd:double" />
<xsd:element name="DistanceMeters" type="xsd:double" />
<xsd:element name="MaximumSpeed" type="xsd:double" minOccurs="0" />
<xsd:element name="Calories" type="xsd:unsignedShort" />
<xsd:element name="AverageHeartRateBpm" type="HeartRateInBeatsPerMinute_t" minOccurs="0" />
<xsd:element name="MaximumHeartRateBpm" type="HeartRateInBeatsPerMinute_t" minOccurs="0" />
<xsd:element name="Intensity" type="Intensity_t" />
<xsd:element name="Cadence" type="CadenceValue_t" minOccurs="0" />
<xsd:element name="TriggerMethod" type="TriggerMethod_t" />
<xsd:element name="Track" type="Track_t" minOccurs="0" maxOccurs="unbounded" /> <!-- Notice that maxOccurs is unbounded so "Track" needs to be a list -->
<xsd:element name="Notes" type="xsd:string" minOccurs="0" />
<xsd:element name="Extensions" type="Extensions_t" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
You can extend Training Center by adding your own elements from another schema here.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="StartTime" type="xsd:dateTime" use="required" />
</xsd:complexType>
and
<xsd:complexType name="Track_t">
<xsd:sequence>
<xsd:element name="TrackPoint" type="TrackPoint_t" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>

Related

How to alternate XML Elements during XML serialization in C#?

I have an XSD schema that has been given to us by a data provider. I cannot modify it. I generated the classes using the XSD.exe command line tool. For everything it works perfectly, I can create my objects in C#, serialize it in XML and validate it against the XSD.
I have a problem with a small portion of it. The expected output is:
<Physical>
<Class>P</Class>
<Capacity>14</Capacity>
<Class>J</Class>
<Capacity>64</Capacity>
<Class>W</Class>
<Capacity>1</Capacity>
<Class>Y</Class>
<Capacity>2</Capacity>
</Physical>
<Saleable Protected="true">
<Class>P</Class>
<Capacity>14</Capacity>
<Class>J</Class>
<Capacity>64</Capacity>
<Class>W</Class>
<Capacity>1</Capacity>
<Class>Y</Class>
<Capacity>2</Capacity>
</Saleable>
As you can see, the child elements of Physical and Sealable alternate (i.e. Class, then Capacity, then Class, then Capacity, etc.).
This is the code of the class that was generated by XSD.exe:
public partial class ClassA
{
private string[] classField;
private Integerctype[] capacityField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("Class", DataType = "token")]
public string[] Class
{
get
{
return this.classField;
}
set
{
this.classField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("Capacity", IsNullable = true)]
public Integerctype[] Capacity
{
get
{
return this.capacityField;
}
set
{
this.capacityField = value;
}
}
}
And the output I receive after the serialization:
<Physical>
<Class>P</Class>
<Class>J</Class>
<Class>W</Class>
<Class>Y</Class>
<Capacity>14</Capacity>
<Capacity>64</Capacity>
<Capacity>1</Capacity>
<Capacity>2</Capacity>
</Physical>
<Saleable>
<Class>P</Class>
<Class>J</Class>
<Class>W</Class>
<Class>Y</Class>
<Capacity>14</Capacity>
<Capacity>64</Capacity>
<Capacity>1</Capacity>
<Capacity>2</Capacity>
</Saleable>
As you can see, we lost the alternation between Class and Capacity...
I tried to use the Order property of the XmlElementAttribute: the Class property was decorated with Order = 1, and the Capacity property was decorated with Order = 2, but it did not help. Example:
[System.Xml.Serialization.XmlElementAttribute("Class", DataType = "token", Order = 1)]
public string[] Class
During the validation, with or without the Order property, I receive errors as follow:
The element 'Physical' in namespace 'xxx' has invalid child element
'Class' in namespace 'xxx'. List of possible elements expected:
'Capacity' in namespace 'xxx'.
Finally, here is the portion of the XSD:
<xsd:element name="ClassA" minOccurs="0">
<xsd:complexType>
<xsd:all>
<xsd:element name="Physical" minOccurs="0">
<xsd:annotation>
<xsd:documentation>True, physical class A configuration</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence minOccurs="0" maxOccurs="unbounded">
<xsd:element name="Class" type="CabinClass.type" />
<xsd:element name="Capacity" type="Integer.ctype" nillable="true" />
</xsd:sequence>
<xsd:attributeGroup ref="Array.attgroup" />
</xsd:complexType>
</xsd:element>
<xsd:element name="Saleable" minOccurs="0">
<xsd:annotation>
<xsd:documentation>Class A configuration for sales purposes</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence minOccurs="0" maxOccurs="unbounded">
<xsd:element name="Class" type="CabinClass.type" />
<xsd:element name="Capacity" type="Integer.ctype" nillable="true" />
</xsd:sequence>
<xsd:attributeGroup ref="Array.attgroup" />
</xsd:complexType>
</xsd:element>
</xsd:all>
<xsd:attributeGroup ref="Container.attgroup" />
</xsd:complexType>
</xsd:element>
My guess is that it is related to the presence of xsd:sequence. But as I said, I do not want to modify the XSD as it is provided by a data provider and we must ensure that the XML we generate is fully compatible.
Any idea how can I solve this problem?
Simplified code could be this:
public class Physical
{
[XmlElement("Capacity", typeof(int))]
[XmlElement("Class", typeof(string))]
public object[] Items { get; set; }
}
This will ensure correct deserialization and give the serialization of the elements in the order in which they are placed in the array.
A working version might look like this:
public class Physical
{
[EditorBrowsable(EditorBrowsableState.Never)]
[XmlElement("Capacity", typeof(int))]
[XmlElement("Class", typeof(string))]
public object[] Items
{
get
{
object[] items = new object[Class.Length * 2];
for (int i = 0; i < items.Length; i += 2)
{
items[i] = Class[i / 2];
items[i + 1] = Capacity[i / 2];
}
return items;
}
set
{
Class = new string[value.Length / 2];
Capacity = new int[value.Length / 2];
for (int i = 0; i < value.Length; i += 2)
{
Class[i / 2] = (string)value[i];
Capacity[i / 2] = (int)value[i + 1];
}
}
}
[XmlIgnore]
public string[] Class { get; set; }
[XmlIgnore]
public int[] Capacity { get; set; }
}
Change int to Integerctype, add DataType parameter.
Similarly, change the second class.

xml file validating in notepad++ but not in C#

I have the following xsd snippet:
<xs:element name="TR" type="tns:blah" />
<xs:complexType name="blah">
<xs:sequence>
<xs:element minOccurs="1" maxOccurs="1" name="Res" type="tns:Res" />
<xs:element minOccurs="0" maxOccurs="1" name="SNotifications" type="tns:ArrayOfSNotification" />
<xs:element minOccurs="0" maxOccurs="1" name="UNotifications" type="tns:ArrayOfUNotification" />
<xs:element minOccurs="0" maxOccurs="1" name="TNotifications" type="tns:ArrayOfTNotification" />
</xs:sequence>
</xs:complexType>
and I have the following xml:
<TR xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://something.com/something">
<Res>
<CC>CMG</CC>
<CT>2014-07-24T14:10:03.84</CT>
<BN>994807</BN>
</Res>
<SNotifications xmlns="http://something.com/something" />
<UNotifications xmlns="http://something.com/something" />
<TNotifications xmlns="http://something.com/something" />
</TR>
I get no error validation the xml in notepad++.
but i get an error while using C#.
The error is:
exception:System.Xml.Schema.XmlSchemaValidationException: The element 'TR' in namespace 'http://something.com/something' has invalid child element 'SNotifications'. List of possible elements expected: 'SNotifications, TNotifications, UNotifications'
the C# code i use is:
xmlDocument.Schemas.Add("http://www.something.com/something", "path to xsd file");
string result = string.Empty;
xmlDocument.Validate((s, e) => result = string.Format("exception:{0}, exceptionmessage:{1}", e.Exception, e.Message));
I have already loaded the xml document.
Any help would be very much appreciated.
Thank you in advance,
gmat
Please try this.
public static bool IsValidXml(string xmlFilePath, string xsdFilePath)
{
var xdoc = XDocument.Load(xmlFilePath);
var schemas = new XmlSchemaSet();
schemas.Add(namespaceName, xsdFilePath);
Boolean result = true;
xdoc.Validate(schemas, (sender, e) =>
{
result = false;
});
return result;
}
We need to know the targetNamespace of your schema document, and the setting of elementFormDefault. Almost certainly it's one of the following:
(a) you have elementFormDefault="qualified", and the target namespace of the schema is not http://something.com/something (in which case the SNotifications element should be in the target namespace); or
(b) you don't have elementFormDefault="qualified" (in which case SNotifications should be in no namespace).

Data at the root level is invalid. Line 1, position 1 on valid in memory xml

I have a very valid XMl string in memory downloaded from an OGC complaint web feature service.
When I use the following code to create am XmlTextReader to parse to my parser,
using (var sr = new StringReader(schemaString))
{
using (var reader = new XmlTextReader(sr))
{
try
{
schema = new GML2Parser().GetClassDefinition(reader, schema);
}
catch (Exception ex)
{
error = ex.Message;
}
}
}
I get an exception indicating Data at rool level is invalid. If I save this string to a local file say feature_desc.xsd the use File.ReadAllText and call the aforementioned routine, I run into a similar problem.
However, if I use XmlReader.Create(feature_desc.xsd), my parser does not throw an exception when it starts traversing the XML nodes. This is a method that summarizes these actions;
private void ParseFeatureDescription(DataTableInfo schema, string featureDescription, string featureFileName, string featureName)
{
var schemaLocation = string.Empty;
if (featureFileName != null)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(featureDescription);
schemaLocation = infrut.Utilities.CreateTempFilePath(featureFileName, FileExtension.xsd, false);
doc.Save(schemaLocation);
}
var error = DeserializeTableSchema(schema, featureDescription, featureName);
if (!string.IsNullOrEmpty(error))
{
var fromFileFeatureDesc = File.ReadAllText(schemaLocation);
if (featureDescription == fromFileFeatureDesc){}
error = DeserializeTableSchema(schema, fromFileFeatureDesc, featureName);
if (!string.IsNullOrEmpty(error))
{
// last resort
var reader = XmlReader.Create(schemaLocation);
schema = new GML2Parser().GetClassDefinition(reader, schema);
if (schema.Columns.Count == 0)
{
// trouble
ActionResponse.LogError("Error parsing description of " + featureName + ". Inner exception is \r\n" + error
+ " " + " for content \r\n" + fromFileFeatureDesc, "WFS Worker");
}
}
}
}
In memory representation of the string is:
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:ems=\"http://www.emssatcom.com\" xmlns:gml=\"http://www.opengis.net/gml\" elementFormDefault=\"qualified\" targetNamespace=\"http://www.emssatcom.com\">\r\n <xsd:import namespace=\"http://www.opengis.net/gml\" schemaLocation=\"http://10.25.131.62:8091/geoserver/schemas/gml/2.1.2/feature.xsd\" />\r\n <xsd:complexType name=\"asmcc_srr_viewType\">\r\n <xsd:complexContent>\r\n <xsd:extension base=\"gml:AbstractFeatureType\">\r\n <xsd:sequence>\r\n <xsd:element maxOccurs=\"1\" minOccurs=\"0\" name=\"gid\" nillable=\"true\" type=\"xsd:int\" />\r\n <xsd:element maxOccurs=\"1\" minOccurs=\"0\" name=\"srr_name\" nillable=\"true\" type=\"xsd:string\" />\r\n <xsd:element maxOccurs=\"1\" minOccurs=\"0\" name=\"the_geom\" nillable=\"true\" type=\"gml:PolygonPropertyType\" />\r\n </xsd:sequence>\r\n </xsd:extension>\r\n </xsd:complexContent>\r\n </xsd:complexType>\r\n <xsd:element name=\"asmcc_srr_view\" substitutionGroup=\"gml:_Feature\" type=\"ems:asmcc_srr_viewType\" />\r\n</xsd:schema>"
and persisted file is:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ems="http://www.emssatcom.com" xmlns:gml="http://www.opengis.net/gml" elementFormDefault="qualified" targetNamespace="http://www.emssatcom.com">
<xsd:import namespace="http://www.opengis.net/gml" schemaLocation="http://10.25.131.62:8091/geoserver/schemas/gml/2.1.2/feature.xsd" />
<xsd:complexType name="asmcc_srr_viewType">
<xsd:complexContent>
<xsd:extension base="gml:AbstractFeatureType">
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="0" name="gid" nillable="true" type="xsd:int" />
<xsd:element maxOccurs="1" minOccurs="0" name="srr_name" nillable="true" type="xsd:string" />
<xsd:element maxOccurs="1" minOccurs="0" name="the_geom" nillable="true" type="gml:PolygonPropertyType" />
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="asmcc_srr_view" substitutionGroup="gml:_Feature" type="ems:asmcc_srr_viewType" />
</xsd:schema>
Any one run into this?
Wild guess here: sometimes I get this error (line 1 col 1) in different applications because they stored in UTF-8 encoding and they have byte order mark at the very beginning of the text/file.
http://en.wikipedia.org/wiki/Byte_order_mark
Try to read file as ANSI string, not unicode

C# Web Service client cast error

I am trying to consume a Java web service but get an exception System.InvalidCastException: Cannot assign object of type ValueArrayType to an object of type ValueArrayType[]
I am consuming a third party service so cannot change the service and have been informed that they can consume the service ok with php and java.
Value Array type is complex type
<xsd:complexType name="ValueArrayType">
<xsd:sequence>
<xsd:element name="ValueName" type="xsd:string"/>
<xsd:element name="ValueType" type="xsd:string"/>
<xsd:element name="ValueValue" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
It is an element in the response DetailsType that can have several occurrences as it has max = unbound and is wrapped by a sequence attribute.
<xsd:complexType name="DetailsType">
<xsd:sequence>
<xsd:element name="Id" type="xsd:int"/>
<xsd:element name="MobileName" type="xsd:string"/>
<xsd:element name="ValueArray" type="tns:ValueArrayType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
I have tried wsdll.exe and svrcutil.exe to try and generate client code.
the ValueArrayType is defined in the generated code as an array.
public ValueArrayType[] ValueArray
{
get
{
return this.valueArrayField;
}
set
{
this.valueArrayField = value;
}
}
an example of the data coming back is.
....
<Details xsi:type="tns:DetailsType">
<Id xsi:type="xsd:int">9999</Id>
<ValueArray xsi:type="tns:ValueArrayType">
<ValueName xsi:type="xsd:string">Count</ValueName>
<ValueType xsi:type="xsd:string">numeric</ValueType>
<ValueValue xsi:type="xsd:string">11</ValueValue>
</ValueArray>
<ValueArray xsi:type="tns:ValueArrayType">
<ValueName xsi:type="xsd:string">Start</ValueName>
<ValueType xsi:type="xsd:string">numeric</ValueType>
<ValueValue xsi:type="xsd:string">31</ValueValue>
</ValueArray>
<ValueArray xsi:type="tns:ValueArrayType">
<ValueName xsi:type="xsd:string">A1</ValueName>
<ValueType xsi:type="xsd:string">numeric</ValueType>
<ValueValue xsi:type="xsd:string">23</ValueValue>
</ValueArray>
<ValueArray xsi:type="tns:ValueArrayType">
<ValueName xsi:type="xsd:string">A2</ValueName>
<ValueType xsi:type="xsd:string">numeric</ValueType>
<ValueValue xsi:type="xsd:string">0</ValueValue>
</ValueArray>
<ValueArray xsi:type="tns:ValueArrayType">
<ValueName xsi:type="xsd:string">X1</ValueName>
<ValueType xsi:type="xsd:string">numeric</ValueType>
<ValueValue xsi:type="xsd:string">0</ValueValue>
</ValueArray>
.....
If I change the client code to public ValueArrayType ValueArray
instead of an array then the client works but only gets the first ValueArray returned.
Have tried suggestions from http://blogs.msdn.com/b/netcfteam/archive/2007/02/01/why-your-netcf-apps-fail-to-call-some-web-services.aspx.
Update
I have generated a WCF Service with the proxyclass generated from scvutil.
When I consume and check the xml with WCFTestCLient.exe.
An Array type is sent back as
<ValueArray>
<ValueArrayType>
<ValueName>a</ValueName>
<ValueType>string</ValueType>
<ValueValue>1</ValueValue>
</ValueArrayType>
<ValueArrayType>
<ValueName>a</ValueName>
<ValueType>string</ValueType>
<ValueValue>2</ValueValue>
</ValueArrayType>
</ValueArray>
I assume either the data being sent does not match the WSDL or there is a bug in the C# scvutil, or System.ServiceModel.
Try to specify your element type inside the generated code
[XmlElement(ElementName = "ValueArray", Type = typeof(ValueArrayType), Namespace = "YourSchemaNamespace")]
public ValueArrayType[] ValueArray
{
get
{
return this.valueArrayField;
}
set
{
this.valueArrayField = value;
}
}
More information is available at MSDN
The problem is caused by incorrect xsi:type values that mislead WCF deserialization (described here).
The workaround is to use OperationFormatUse.Literal instead of OperationFormatUse.Encoded on all operations.
Can you try something like this ?
JavaServecie js= new JavaService();
js.ValueArrayType arr= js.GetValues(.....
if the class is public.

The Attribute of "ref" for XML Schema For C# Parse

Good day.
I got a problem about the attribute of "ref" for my XSD file.
My code :
using System;
using System.Collections;
using System.Xml;
using System.Xml.Schema;
class XmlSchemaTraverseExample
{
static void Main()
{
// Add the customer schema to a new XmlSchemaSet and compile it.
// Any schema validation warnings and errors encountered reading or
// compiling the schema are handled by the ValidationEventHandler delegate.
XmlSchemaSet schemaSet = new XmlSchemaSet();
schemaSet.ValidationEventHandler += new ValidationEventHandler(ValidationCallback);
schemaSet.Add("http://www.w3.org/2001/XMLSchema", "recipe.xsd");
schemaSet.Compile();
// Retrieve the compiled XmlSchema object from the XmlSchemaSet
// by iterating over the Schemas property.
XmlSchema customerSchema = null;
foreach (XmlSchema schema in schemaSet.Schemas())
{
customerSchema = schema;
}
// Iterate over each XmlSchemaElement in the Values collection
// of the Elements property.
foreach (XmlSchemaElement element in customerSchema.Elements.Values)
{
Console.WriteLine("Element: {0}", element.Name);
// Get the complex type of the Customer element.
XmlSchemaComplexType complexType = element.ElementSchemaType as XmlSchemaComplexType;
// If the complex type has any attributes, get an enumerator
// and write each attribute name to the console.
if (complexType.AttributeUses.Count > 0)
{
IDictionaryEnumerator enumerator =
complexType.AttributeUses.GetEnumerator();
while (enumerator.MoveNext())
{
XmlSchemaAttribute attribute =
(XmlSchemaAttribute)enumerator.Value;
Console.WriteLine("Attribute: {0}", attribute.Name);
}
}
// Get the sequence particle of the complex type.
XmlSchemaSequence sequence = complexType.ContentTypeParticle as XmlSchemaSequence;
// Iterate over each XmlSchemaElement in the Items collection.
foreach (XmlSchemaElement childElement in sequence.Items)
{
Console.WriteLine("Element: {0}, {1}, {2}", childElement.RefName, childElement.MinOccurs, childElement.MaxOccurs);
}
}
}
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);
}
}
my XSD file
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="Recipe">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="DocumentInfo" minOccurs="1" maxOccurs="1" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<!-- Element of DocumentInfo -->
<xsd:element name="DocumentInfo">
<xsd:complexType>
<xsd:attribute name="Name" type="xsd:string" />
<xsd:attribute name="Description" type="xsd:string" />
<xsd:attribute name="Creator" type="xsd:string" />
<xsd:attribute name="CreateTime" type="xsd:string" />
<xsd:attribute name="Revisor" type="xsd:string" />
<xsd:attribute name="ReviseTime" type="xsd:string" />
<xsd:attribute name="Version" type="xsd:string" />
<xsd:attribute name="Frozen" type="xsd:boolean" />
<xsd:attribute name="ASCSVersion" type="xsd:string" use="optional"/>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Now when i got the output below:
Element: Recipe
Element: http://www.w3.org/2001/XMLSchema:DocumentInfo, 1, 1
Element: http://www.w3.org/2001/XMLSchema:Prerequisite, 1, 1
Element: http://www.w3.org/2001/XMLSchema:Headers, 0, 1
Element: http://www.w3.org/2001/XMLSchema:Steps, 1, 1
How to remove the prefix of "http://www.w3.org/2001/XMLSchema" ?
I can only take use of the Attribute of "childElement.RefName", I can't find "childElement.Ref".
DEV IDE: VS2005. .NET 2.0.
Thanks in advance here.
BR!
Nano
You can either use childElement.Name or childElement.QualifiedName.Name
XmlSchemaElement.Name
XmlSchemaElement.QualifiedName

Categories