How to omit XML element in C# XML generated from XSD? - c#

Minoccurs is 0 in the XSD and nillable is true for an element.
But if I don't set the element value, it takes it as null and the record is blanked out on the server. Is there a way to tell it to omit the element from the output XML when some conditions are satisfied but have it for other cases?
<xs:element name='CLS_CD' minOccurs='0' nillable='true' type='xdv:stringLen20'/>

If you are using XmlSerializer, you can control whether the value is emitted by including a PropertyNameSpecified property.
Another option is to use a special
pattern to create a Boolean field
recognized by the XmlSerializer, and
to apply the XmlIgnoreAttribute to the
field. The pattern is created in the
form of propertyNameSpecified. For
example, if there is a field named
"MyFirstName" you would also create a
field named "MyFirstNameSpecified"
that instructs the XmlSerializer
whether to generate the XML element
named "MyFirstName".
For example, if you declare the class like this:
public class Data
{
[XmlIgnore]
public bool CLS_CDSpecified { get; set; }
[XmlElement(IsNullable=true)]
public string CLS_CD { get; set; }
}
Then you can serialize nothing, an explicit nil value, or an actual value:
var serializer = new XmlSerializer(typeof(Data));
var serializesNothing = new Data();
serializesNothing.CLS_CD = null;
serializesNothing.CLS_CDSpecified = false;
serializer.Serialize(Console.Out, serializesNothing);
Console.WriteLine();
Console.WriteLine();
var serializesNil = new Data();
serializesNil.CLS_CD = null;
serializesNil.CLS_CDSpecified = true;
serializer.Serialize(Console.Out, serializesNil);
Console.WriteLine();
Console.WriteLine();
var serializesValue = new Data();
serializesValue.CLS_CD = "value";
serializesValue.CLS_CDSpecified = true;
serializer.Serialize(Console.Out, serializesValue);
Output:
<?xml version="1.0" encoding="IBM437"?>
<Data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" />
<?xml version="1.0" encoding="IBM437"?>
<Data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<CLS_CD xsi:nil="true" />
</Data>
<?xml version="1.0" encoding="IBM437"?>
<Data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<CLS_CD>value</CLS_CD>
</Data>

Related

XML xsi:nil="true" value set but returning null

I have given XML doc:
<root>
<element xsi:nil="true" />
<root>
Later on in code the element gets updated to:
<root>
<element xsi:nil="true">some data</element>
</root>
No whey I try to deserialize the element in to an object the "element" property is null. What am I doing wrong?
Here is the C# code I use to deserialize:
XmlSerializer reader = new XmlSerializer(typeof(MyObject));
StreamReader srFile = new StreamReader(strFilePath);
MyObject obj = (MyObject)reader.Deserialize(srFile);
[Serializable]
public class My Object
{
[XmlElement(IsNullable = true)]
public string Element {get; set;}
}
I was able to do a nodeName.RemoveAttribute("xsi:nil") before setting the value. Seems like there should be a way to do this when setting the element value since the value of the element would no longer be null.

how to remove nodes in an xml that is inside another xml

I have an xml as an value of an element inside a Main xml. I want to scrub off or delete a node within the inner xml. How do I achieve that ?
For removing a node in main xml I am doing
var result = doc.Descendants("node1").Where(x => x.Attribute("id").Value == "002");
if (result != null)
{
result.Remove();
}
Here is my XML :
<?xml version="1.0" encoding="utf-16"?>
<root>
<node1>id="001" version="1.0"</node1>
<node2>id="002" version="1.0"</node1>
<report>raw = "<response = "10"><innerxml><prod>date = "18082016" name="pqr"</prod><seg1>id="002" name = "sqs"</seg1></innerxml></response>"</report>
</root>
Your code is correct but your xml is not. the XML should be like:
<?xml version="1.0" encoding="utf-16"?>
<root>
<node1 id="001" version="1.0"></node1>
<node2 id="002" version="1.0"></node2>
</root>

C# Serialize List to XML with Sequence attribute autogenerated?

I have to generate (serialize to) XML from object with array of (Order) elements.
Order class generated from XSD has sequence attribute:
[System.Xml.Serialization.XmlAttributeAttribute(DataType = "token")]
public string Sequence;
I am using .Net XMLSerializer, but it does not generate automagically for every Order element Sequence attribute.
Having:
Order[] Orders = new Order[2] {...}
I have to get:
<Order Sequence="1">..</Order>
<Order Sequence="2">..</Order>
And for just one, single element it should render:
<Order Sequence="1">..</Order>
Does anyone know how to make XMLSerialzier renders this attribute automagically? Or do I need to manually set Sequence for every Order element?
Cheers
AFAIK there is no way to achieve this with out-of-the-box methods. This leaves you with the following options:
IXmlSerializable
Implement IXmlSerializable on the object that contains the array of Orders. This way, you can either serialize the Orders manually or set the sequence number of the Order before serializing the object into the XmlWriter using the XmlSerializer.Serialize method:
public class OrdersContainer : IXmlSerializable
{
public Order[] Orders;
public void WriteXml(XmlWriter writer)
{
// Serialize other properties
writer.WriteStartElement("Orders");
var ser = new XmlSerializer(typeof(Order));
for(var i = 0; i < Orders.Length; i++)
{
Orders[i].Sequence = (i + 1).ToString();
ser.Serialize(writer, Orders[i]);
}
writer.WriteEndElement(); // Orders
}
// ...
}
This generated the following XML:
<?xml version="1.0" encoding="utf-16"?>
<OrdersContainer>
<Orders>
<Order xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Sequence="1">
<Name>Order 1</Name>
</Order>
<Order xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Sequence="2">
<Name>Order 2</Name>
</Order>
</Orders>
</OrdersContainer>
The XmlSerializer places some namespace declarations on the Order elements, but that doesn't hurt. My sample class had a Name property on the Order class.
The downside of this approach is that you have to implement the serialization of the OrdersContainer class manually, including the deserialization.
Linq to XML
The second option is to use Linq to XML for the serialization part. You'd also have to implement the serialization manually, but you could use the otb XmlSerializer for deserialization (on the other hand you might want to avoid to mix two different frameworks). You could serialize the OrdersContainer class as follows and also write the sequence number:
var doc = new XDocument(new XElement("OrdersContainer",
new XElement("Orders",
cont.Orders.Select((x, i) => new XElement("Order",
new XAttribute("Sequence", (i + 1).ToString()),
new XElement("Name", x.Name))))));
doc.Save(writer);
This created the following XML:
<?xml version="1.0" encoding="utf-16"?>
<OrdersContainer>
<Orders>
<Order Sequence="1">
<Name>Order 1</Name>
</Order>
<Order Sequence="2">
<Name>Order 2</Name>
</Order>
</Orders>
</OrdersContainer>
Please note that the sample uses an overload of the Select method that also receives the index of the item so that the sequence number can be created based upon the position in the array.
If order is a class of yours, you can add a property with [XmlAttributeAttribute]
class Order {
[XmlAttribute()]
public int Sequence { get; set; }
But you should set this Sequence property in all items of your list.
this works fine -
var o = new XmlSerializerNamespaces();
o.Add("", "");
var ser = new XmlSerializer(typeof(List<Order>), "");
using (var sw = new StringWriter())
{
ser.Serialize(sw, new List<Order> {
new Order { sequence = "1", MyProperty = 1 },
new Order { sequence = "2", MyProperty = 2 } },
o);
var t = sw.ToString();
}
AND
[XmlAttribute(AttributeName = "sequence", DataType = "string")]
public string sequence { get; set; }

c# deserialize xml from different node

I've got an xml-file that looks like this for example:
<?xml version="1.0" encoding="UTF-8"?>
<Adresses>
<Message>
<Header>
<MessageID>96</MessageID>
<Timestamp>22.08.2014 10:25:01</Timestamp>
</Header>
<Body>
<Person SurName="Muster" Prename="Max">
<Adress Street="Street 1"/>
</Person>
<Person SurName="Muster" Prename="Max">
<Adress Street="Street 1"/>
</Person>
<Person SurName="Muster" Prename="Max">
<Adress Street="Street 1"/>
</Person>
</Body>
</Message>
</Adresses>
From this xml I only want the part inside the body-tags. I do the deserialization with the XmlSerializer and annotaions. So I have models that look like this
[XmlRoot("Body")]
public class BodyXml
{
public BodyXml()
{}
[XmlElement("Person")]
public Person[] Persons { get; set; }
}
Now my question is how can I get the XmlSerializer to serialize from the body-tag and not from the adresses-tag? Do I need another annotation somewhere in my models?
thanks and greets
Depending on other constraints, either consider writing a quick and dirty wrapper that would deserialize the whole XML (with BodyXml as it's member), or alternatively select only the relevant part of your xml, e.g.:
var serializer = new XmlSerializer(typeof(BodyXml));
var xDoc = XDocument.Parse(YOUR_XML_STRING);
using (var xmlReader = xDoc.Descendants("Body").Single().CreateReader())
{
var result = serializer.Deserialize(xmlReader);
}
EDIT: without any context I'd go with the latter.
use XmlIgnoreAttribute
You can Add Address property as below
[XmlIgnoreAttribute]
public AddressClass Adress{get;set;}
Here AddressClass may type of your Address property or some other class.

Deserialize XML using XmlSerializer

I have the follwoing XML
<?xml version="1.0" ?>
<SERVICES.OUTPUTResponse>
<Results>
<Result>
<Dataset name="OutputData">
<Row>
<country>USA</country>
<pubyear>9986</pubyear>
<numart>123</numart>
<numcites>456</numcites>
</Row>
<Row>
<country>USA</country>
<pubyear>97</pubyear>
<numart>895</numart>
<numcites>231</numcites>
</Row>
</Dataset>
<Dataset name="Result 2">
<Row>
<Result_2>
true
</Result_2>
</Row>
</Dataset>
</Result>
</Results>
<_Probe></_Probe>
</SERVICES.OUTPUTResponse>
and i tried to deserialize by using XmlSerializer but it returns null.
The Property class which i used is
public class XMLDetails
{
public string country { get; set; }
public string pubyear { get; set; }
public string numart { get; set; }
public string numcites { get; set; }
}
Deserialize code is
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "SERVICES.OUTPUTResponse";
xRoot.IsNullable = true;
var serializer = new XmlSerializer(typeof(XMLDetails), xRoot);
var reader = new StringReader(remoteXml);
var objpublication = (XMLDetails)(serializer.Deserialize(reader));
Please help me to reslove it
If you want to use Linq To Xml
XDocument xDoc = XDocument.Parse(xml); //or XDocument.Load(filename);
var rows = xDoc.XPathSelectElement("//Dataset[#name='OutputData']")
.Descendants("Row")
.Select(r => new XMLDetails
{
country = r.Element("country").Value,
pubyear = r.Element("pubyear").Value,
numart = r.Element("numart").Value,
numcites = r.Element("numcites").Value,
})
.ToList();
PS: required namespaces System.Xml.Linq and System.Xml.XPath
First you need to use xsd.exe for generating .xsd (schema) file and .cs (class) file
XML Schema Definition Tool (Xsd.exe)
You can run "Visual Studio Command Prompt" and xsd.exe path definition is already defined it is ready to use.
Type the following command in the console
*I assume your xml is saved in "yourxmlfile.xml"
>xsd.exe yourxmlfile.xml
this command will generate "yourxmlfile.xsd" file
then execute the following command for generating .cs file
But before change the
<xs:element name="Results" minOccurs="0" maxOccurs="unbounded"> line with
<xs:element name="Results" minOccurs="0" maxOccurs="1"> in generated xsd file
(to change Results to property instead of array propery)
>xsd.exe yourxmlfile.xsd /c
this command will generate "yourxmlfile.cs"
now you can add this file to your project and you can deserialize xml file as below
var serializer = new XmlSerializer(typeof(SERVICESOUTPUTResponse));
SERVICESOUTPUTResponse instance = null;
using (var fileStream = File.OpenRead(#"c:\path_to\yourxmlfile.xml"))
{
instance = (SERVICESOUTPUTResponse)serializer.Deserialize(fileStream);
}

Categories