Deserializing complex element content to a string with XmlSerializer in C# - c#

Is there any way to deserialize elements containing either simple text or subelement to a string with XmlSerializer?
Xml sample:
<Attribute>
<AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">thisistext</AttributeValue>
<AttributeValue>
<e:Authorities xmlns:e="urn:dummy">
<e:Authority>ORG_CHIEF</esia-encoder:Authority>
</e:Authorities>
</AttributeValue>
</Attribute>
C# property:
[XmlElement("AttributeValue", IsNullable = true)]
public string[] AttributeValue { get; set; }
Deserialization of the first AttributeValue succeed, but the next one fails. No wonder, beacause ReadElementString method expects simple or empty content. I'm looking for a way to tell to serializer "put content of this element to a string, whatever it contains".

Actually, the 2nd value you have in your XML is:
<e:Authorities xmlns:e="urn:dummy">
<e:Authority>ORG_CHIEF</esia-encoder:Authority>
</e:Authorities>
This is no valid string dataType which is expected because of:
public string[] AttributeValue {get; set;}

If you are able to define it in XSD, you can use XSD2Code or xsd.exe to create a class for the XSD to deserialize into.
What about this one?
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="Attribute">
<xs:complexType>
<xs:sequence>
<xs:element name="AttributeValue" maxOccurs="unbounded">
<xs:complexType>
<xs:choice>
<xs:element name="AuthoritiesString" type="xs:string"/>
<xs:element name="AuthoritiesElement">
<xs:complexType>
<xs:sequence>
<xs:element name="Authority"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

Related

How to iterate/traverse XML file elements( which contains different namespaces) to convert it as Data table in C#

I have a sample to read a xml schema set for a xml file which contains different namespaces. For this i can get different schema for each namespace as i explained below.
Sample File:
<?xml version="1.0" encoding="utf-8"?>
<data xmlns:d="http://sampleschema/dataservices" xmlns:m="http://sampleschema/dataservices/metadata">
<content>
<m:properties>
<d:CustomerID>ALFKI</d:CustomerID>
<d:CompanyName>Alfreds Futterkiste</d:CompanyName>
</m:properties>
</content>
</data>
Sample Code to get XML Schema Set:
strFileName = #"C:\Sample\Sample.xml";
XmlReader reader = XmlReader.Create(strFileName);
XmlSchemaInference schema = new XmlSchemaInference();
XmlSchemaSet schemaSet = schema.InferSchema(reader);
It gives three different types of schemas while using the above code. But my requirement will be i need a single schema for the entire xml file which contain any number of namespaces in it. I have checked with possibilities of codes in msdn and stack overflow. I can't find any proper solution for this.
The expected schema output will be like below.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="data">
<xs:complexType>
<xs:sequence>
<xs:element name="content">
<xs:complexType>
<xs:sequence>
<xs:element name="m:properties">
<xs:complexType>
<xs:sequence>
<xs:element name="d:CustomerID" type="xs:string"></xs:element>
<xs:element name="d:CompanyName" type="xs:string"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="xmlns:d" type="xs:string"></xs:attribute>
<xs:attribute name="xmlns:m" type="xs:string"></xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
Any one can help to achieve this requirement.
Thanks in advance.
Try something like this :
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:m="http://www.w3.org/2001/XMLSchema" xmlns:d="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="data">
<xs:complexType>
<xs:sequence>
<xs:element name="content">
<m:complexType>
<m:sequence>
<m:element name="properties">
<d:complexType>
<d:sequence>
<d:element name="CustomerID" type="xs:string"></d:element>
<d:element name="CompanyName" type="xs:string"></d:element>
</d:sequence>
</d:complexType>
</m:element>
</m:sequence>
</m:complexType>
</xs:element>
</xs:sequence>
<d:attribute name="xmlns_d" type="d:string"></d:attribute>
<m:attribute name="xmlns_m" type="d:string"></m:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

Unexpected output of xsd.exe

Consider the following simple schema:
<xs:schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="MyRoot">
<xs:complexType>
<xs:sequence>
<xs:group ref="MyChoice" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:group name="MyChoice">
<xs:choice>
<xs:element name="a" type="xs:string"/>
<xs:element name="b" type="xs:string"/>
<xs:element name="c" type="xs:string"/>
</xs:choice>
</xs:group>
</xs:schema>
When turning this into C# code with xsd.exe (VS2017), I get the following output:
public partial class MyRoot {
private string[] aField;
private string[] bField;
private string[] cField;
// ... omitted for brevity ...
}
This code has a major problem: in the XSD/XML all of the sub-elements (a, b and c) were ordered.
This order is now lost in the C# class, since there are three different arrays for each of the sub elements.
Is xsd.exe doing it wrong? Or am I using it wrong? Or is the .xsd file flawed?

The XSD tool skips a nested level

I hope I am correctly phrasing my problem. When we run the xsd tool on our xsd to create classes, the code is not exactly representing the xsd on one section. It is like this:
XSD: 'BaliseGroups' => Collection of 'BaliseGroup' => Collection of 'Balise'
Code: 'BaliseGroups' => Collection of type 'Balise' named 'BaliseGroup'...
<xs:element name="BaliseGroups">
<xs:annotation>
<xs:documentation>Een verzameling balisegroepen</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="BaliseGroup" type="tBaliseGroup"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="tBaliseGroup">
<xs:annotation>
<xs:documentation>Een balisegroep, </xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="Balise" type="tBalise" minOccurs="1" maxOccurs="8"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="tBalise">
<xs:annotation>
<xs:documentation>Type voor een balise</xs:documentation>
</xs:annotation>
<xs:complexContent>
<xs:extension base="tTrackAsset"/>
</xs:complexContent>
</xs:complexType>
Code
public partial class BaliseGroups
{
private tBalise[] baliseGroupField;
/// <remarks/>
[System.Xml.Serialization.XmlArrayItemAttribute("Balise", IsNullable = false)]
public tBalise[] BaliseGroup
{
get
{
return this.baliseGroupField;
}
set
{
this.baliseGroupField = value;
}
}
}
As you can see in the generated C# code block it creates a Property BaliseGroup of type Balise[]. This should be of type tBaliseGroup[].
I have a conjecture that there is something wrong with the xsd, but I cannot figure out what..
I have solved my problem. By annotating in the xsd that 'BaliseGroup' has a maxOccurs of 'unbounded' it creates the collection of 'BaliseGroup' in 'BaliseGroups'. Here is the change:
<xs:element name="BaliseGroups">
<xs:annotation>
<xs:documentation>Een verzameling balisegroepen</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="BaliseGroup" type="tBaliseGroup" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>

How to cause the WSDL generated by WCF to contain an xsd:any element?

So, I have the following data contract:
[DataContract(Namespace = "http://abc/Services/Data")]
public abstract class AbcObject
{
[DataMember]
[XmlAnyElement]
public XmlElement[] Any { get; set; }
}
My expectation is to see the following corresponding xs:complexType element in the generated wsdl:
<xs:complexType name="AbcObject">
<xs:sequence>
<xsd:any minOccurs="0"/>
</xs:sequence>
</xs:complexType>
However, what I actually see is:
<xs:complexType name="AbcObject">
<xs:sequence>
<xs:element name="Any" type="q1:ArrayOfXmlElement" nillable="true" minOccurs="0" xmlns:q1="http://schemas.datacontract.org/2004/07/System.Xml"/>
</xs:sequence>
</xs:complexType>
So, this is not what I want, but I am kind of puzzled how to get the xsd:any generated for me.
Any ideas?
EDIT 1
As per jamiemeyer advice I have changed the DFObject.Any property to be of type XmlAttribute[]. Here is the result:
<xs:complexType name="DFObject">
<xs:sequence>
<xs:element name="Any" type="q1:ArrayOfArrayOfanyType" nillable="true" minOccurs="0" xmlns:q1="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
</xs:sequence>
</xs:complexType>
Although the result is different, it is still not xsd:any.

I need to create an object that can take the key value pair similar to this xsd

This is an example of an XSD for one of the templates that will be stored in the database. The "to_email", "first_name" etc are all tokens and I need to dynamically create a dictionary or an object that can be returned to the client that will give a list of these tokens. The idea behind this is if there is any change in a template then we will just insert another value in the database and it should automatically be created dynamically for returning it to client when they will query for this template.
How do I go about creating/parsing this?
I don't want create a class object with individual element as that would mean that I will have to change it for every addition of the elements. So it has to be something generic.
We should be able to return the set as JSON or XML based on what the client asks for.
How do I go about doing this?
Any help would be appreciated.
Thank you in advance.
<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="http://tempuri.org/XMLSchema.xsd"
elementFormDefault="qualified" xmlns="http://tempuri.org/XMLSchema.xsd"
xmlns:mstns="http://tempuri.org/XMLSchema.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="claim">
<xs:complexType>
<xs:sequence>
<xs:element name="to_email" type="xs:string"/>
<xs:element name="first_name" type="xs:string"/>
<xs:element name="last_name" type="xs:string"/>
<xs:element name="url" type="xs:string"/>
<xs:element name="received_date" type="xs:date"/>
<xs:element name="contact_number" type="xs:string"/>
<xs:element name="employer_name" type="xs:string"/>
<xs:element name="er_label" type="xs:string"/>
<xs:element name="er_flag" type="xs:integer"/>
<xs:element name="benefit_id" type="xs:integer"/>
<xs:element name="employee_id" type="xs:integer"/>
<xs:element name="employer_id" type="xs:integer"/>
<xs:element name="form_id" type="xs:integer"/>
<xs:element name="er_url" type="xs:string"/>
<xs:element name="tax" type="xs:string"/>
<xs:element name="Repeater" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="form_id" type="xs:integer"/>
<xs:element name="amount" type="xs:integer"/>
<xs:element name="expense_name" type="xs:string"/>
<xs:element name="date_of_service" type="xs:string"/>
<xs:element name="status_of_claim" type="xs:string"/>
<xs:element name="status_reason"/>
<xs:element name="Order_by" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Adding further comments:
The response to the client should be something like each property of the object representing a field. For example a object.
{
‘field1’: <FieldDefinition>
‘field2’: <FieldDefinition>
‘field3’: <FieldDefinition>
.
.
.
}
The object would contains the following properties like Type for example if it is a string or int, Display name i.e. the internal name could be first_name but the display name would FirstName# etc.
Also the could be an array as well. So this makes it little more complex.
Am I making any sense?
I believe you can do the XML processing or you can find that in Google. Plenty of examples are there. I just added the code for logic you have mentioned for the properties. //Your XML processing
var fields = new List<FieldDefinition>
{
new FieldDefinition{ Type="string", DisplayName="FirstName"},
new FieldDefinition{ Type="int", DisplayName="EmployeeId"}
};
var infr = new List<Infrastructure>
{
new Infrastructure { def1=fields.FirstOrDefault()}// loop through to assign each item
};
foreach (var item in infr)
Console.WriteLine(item.def1.DisplayName + " -" + item.def1.Type);
Console.Read();
}
}
public class Infrastructure
{
public FieldDefinition def1 { get; set; }
}
public class FieldDefinition
{
public string Type { get; set; }
public string DisplayName { get; set; }
}
You generate classes for them using the xsd.exe util
Seen here:
How to generate .NET 4.0 classes from xsd?
xsd your.xsd /classes
You can parse your template using XPath query or any generic XML processing. For any template change, you can opt for CacheDependency for File. You just cache the whole xml and if any changes to the tag/file then you insert that portion to the database and reload the cache. You can try SQLDependency also to get similar work.
Another option, you can go for filesystemwatcher which will raise event for changing in the file content. Then you just need to insert the added portion in the database.

Categories