XML - Get Element Value - C# - c#

I am trying to find if an element value exists then get a element value below it. i.e.
<Reply>
<customer id="1223">
<group>A</group>
<class>
<custclass>AB</custclass>
<custval>1</custval>
</class>
<class>
<custclass>CD</custclass>
<custval>2</custval>
</class>
</customer>
</Reply>
I need to get the custval element value if the custclass = "CD". What is the best way to set this into a string in C# "2"? So I am looking for if custclass element value of "CD" exists then return the custval element value of 2.
Thanks for any info.

We can read the property value using various ways-
Method 1 - using XmlDocument
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
XmlNodeList xnl = doc.SelectNodes("/Reply/customer/class");
foreach (XmlNode node in xnl)
{
if (node.ChildNodes[0].InnerText == "CD")
{
Console.WriteLine(node.ChildNodes[1].InnerText);
}
}
Method 2 - using XDcoument and LINQ
XDocument xml = XDocument.Load(xmlFile);
var result = xml.Root.DescendantsAndSelf("class")
.Where(r => (string)r.Element("custclass").Value == "CD")
.Select(s=> (string)s.Element("custval").Value).Single();
Console.WriteLine(result);
Method 3 - using XDocument and XPathSelectElement
var custval = xml.XPathSelectElement("Reply/customer/class[custclass='CD']/custval").Value;
Console.WriteLine(custval);
Method 4 - using XmlSerializer
Create C# classes using xmltocsharp & use Deserialize to convert the xml to object
[XmlRoot(ElementName = "class")]
public class Class
{
[XmlElement(ElementName = "custclass")]
public string Custclass { get; set; }
[XmlElement(ElementName = "custval")]
public string Custval { get; set; }
}
[XmlRoot(ElementName = "customer")]
public class Customer
{
[XmlElement(ElementName = "group")]
public string Group { get; set; }
[XmlElement(ElementName = "class")]
public List<Class> Class { get; set; }
[XmlAttribute(AttributeName = "id")]
public string Id { get; set; }
}
[XmlRoot(ElementName = "Reply")]
public class Reply
{
[XmlElement(ElementName = "customer")]
public Customer Customer { get; set; }
}
static async System.Threading.Tasks.Task Main(string[] args)
{
string xmlFile = #"xxxxxx.xml";
using (StreamReader r = new StreamReader(xmlFile))
{
string xmlString = r.ReadToEnd();
XmlSerializer ser = new XmlSerializer(typeof(Reply));
using (TextReader reader = new StringReader(xmlString))
{
var result = (Reply)ser.Deserialize(reader);
var custvalue = result.Customer.Class.Where(i => i.Custclass == "CD").Select(a => a.Custval).Single();
Console.WriteLine(custvalue);
}
}
}

Related

xml creation in C#

I want final xml as follows...
<Programs>
<Program><id>4</id><isRead>true</isRead><isWrite>false</isWrite></Program>
<Program><id>8</id><isRead>true</isRead><isWrite>true</isWrite></Program>
</programs>
now following is the code written
XmlDocument xmlDoc = new XmlDocument();
XmlNode rootNode = xmlDoc.CreateNode(XmlNodeType.Element,"programs",null);
xmlDoc.AppendChild(rootNode);
foreach (dynamic item in access)
{
XmlNode myXmlNode = JsonConvert.DeserializeXmlNode(item.ToString(), "program");
rootNode.AppendChild(myXmlNode); //error
}
where in myXmlNode.InnerXml, I am already getting following
<Program><id>4</id><isRead>true</isRead><isWrite>false</isWrite></Program>
And so, running the loop for all children to add in which is parent. But I am getting error for line //error as marked above. Error is:
The specified node cannot be inserted as the valid child of this node,
because the specified node is the wrong type.
You are trying to insert different type of xml node. You could use ImportNode to apply it.
foreach (dynamic item in access)
{
XmlNode myXmlNode = JsonConvert.DeserializeXmlNode(item.ToString(), "program");
rootNode.AppendChild(rootNode.OwnerDocument.ImportNode(myXmlNode.FirstChild,true));
}
I would recommend you create a model for what you are looking to create in XML, then serialize a list of the model to XML.
The reason being that you will end up with something far more maintainable.
Your model would be something like this:
public class Program
{
public int Id { get; set; }
public bool IsRead { get; set; }
public bool IsWrite { get; set; }
}
And you can serialize it by following this article:
https://support.microsoft.com/en-gb/help/815813/how-to-serialize-an-object-to-xml-by-using-visual-c
I've used the XmlSerializer library myself a few times.
public class Program
{
public int Id { get; set; }
public bool IsRead { get; set; }
public bool IsWrite { get; set; }
}
public class XmlTemplate
{
public List<Program> Programs { get; set; }
}
class MainProgram
{
static void Main(string[] args)
{
var xmlTemplate = new XmlTemplate();
xmlTemplate.Programs = new List<Program>();
xmlTemplate.Programs.Add(new Program() { Id = 123, IsRead = true, IsWrite = false });
xmlTemplate.Programs.Add(new Program() { Id = 456, IsRead = false, IsWrite = true });
var serializer = new XmlSerializer(typeof(XmlTemplate));
var stream = new StringWriter();
serializer.Serialize(stream, xmlTemplate);
Console.WriteLine(stream.ToString());
Console.ReadKey();
}
}
This outputs the XML in the following format:
<XmlTemplate xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Programs>
<Program>
<Id>123</Id>
<IsRead>true</IsRead>
<IsWrite>false</IsWrite>
</Program>
<Program>
<Id>456</Id>
<IsRead>false</IsRead>
<IsWrite>true</IsWrite>
</Program>
</Programs>
</XmlTemplate>

Deserialize xml into class having string values in xml

Let me explain, there is a database table which has 1 XML column named audits and other common types of column.
so is this possible to deserialize below XML into class.
<?xml version="1.0"?>
<entity type="Order">
<id type="System.Int64">146</id>
<ordernumber type="System.String">OD555</ordernumber>
<audits type='System.String'>
<audit>
<item>
<create timestamp='2017-07-19 10:02:13' userid='23' />
</item>
<invoice>
<create timestamp='2017-07-19 10:03:37' userid='45' />
</invoice>
</audit>
</audits>
</entity>
Class:
public class Order
{
public long id { get; set; }
public string ordernumber { get; set; }
public string audits { get; set; }
}
Modifying your model with the attributes XmlType and XmlAnyElement (requires XmlElement as type)
[XmlType("entity")]
public class Order
{
public long id { get; set; }
public string ordernumber { get; set; }
[XmlAnyElement]
public XmlElement audits { get; set; }
}
allows to deserialize the complete XML string like
using (MemoryStream stream = new MemoryStream())
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write(xmlString);
writer.Flush();
stream.Position = 0;
XmlSerializer serializer = new XmlSerializer(typeof(Order));
Order o = (Order)serializer.Deserialize(stream);
}
Now you are able to get the audits as string like
string auditsString = o.audits.InnerXml;
You can also add a property to your model to simplify the access:
public string auditsString
{
get
{
return audits.InnerXml;
}
}
Try xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication68
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
Order order = doc.Descendants("entity").Select(x => new Order()
{
id = (long)x.Element("id"),
ordernumber = (string)x.Element("ordernumber"),
audits = x.Descendants("create").Select(y => (DateTime)y.Attribute("timestamp")).ToList()
}).FirstOrDefault();
}
}
public class Order
{
public long id { get; set; }
public string ordernumber { get; set; }
public List<DateTime> audits { get; set; }
}
}
You can try like this
const string xmlString = #"<columns><column><c1>100</c1><c2>200</c2><cn>300</cn></column><column><c1>111</c1><c2>222</c2><cn>333</cn></column> <column> <c1>MAX Newsletter</c1><c2>OLS Application</c2> <cn>Total funded accounts</cn> </column></columns>";
XDocument doc = XDocument.Parse(xmlString);
if (doc.Root != null)
{
List<Row> items = (from r in doc.Root.Elements("column")
select new Row
{
C1 = (string)r.Element ("C1"),
C2 = (string)r.Element("C2"),
}).ToList();

how to send integer type data in xml

I am creating XML to send data. The data contains multiple datatypes as string, integer and decimal. My XML format and c# code to create it as follows.
<root>
<data>
<struct>
<PartnerCD></PartnerCD>
<UserName> </UserName>
<Password> </Password>
<Action> </Action>
<OfficeCD></OfficeCD>
<ChannelCD></ChannelCD>
<Token></Token>
<Notes> </Notes>
<Products>
<Product>
<ProductID></ProductID>
<SVA></SVA>
<Amount></Amount>
</Product>
</Products>
</struct>
</data>
</root>
And my c# code is
public static string CreateRequestXML(string partnerCd, string userName, string password, string action, string productId, string token, string sva, string amount)
{
XmlDocument doc = new XmlDocument();
XmlElement elemRoot = doc.CreateElement("root");
XmlElement elemData = doc.CreateElement("data");
XmlElement elemStruct = doc.CreateElement("struct");
XmlElement elemProducts = doc.CreateElement("Products");
XmlElement elemProduct = doc.CreateElement("Product");
doc.AppendChild(elemRoot);
elemRoot.AppendChild(elemData);
elemData.AppendChild(elemStruct);
//Insert data here
InsertDataNode(doc, elemStruct, "PartnerCD", partnerCd);
InsertDataNode(doc, elemStruct, "UserName", userName);
InsertDataNode(doc, elemStruct, "Password", password);
InsertDataNode(doc, elemStruct, "Action", action);
InsertDataNode(doc, elemStruct, "Token", token);
elemStruct.AppendChild(elemProducts);
elemProducts.AppendChild(elemProduct);
InsertDataNode(doc, elemProduct, "ProductID", productId);
InsertDataNode(doc, elemProduct, "SVA", sva);
InsertDataNode(doc, elemProduct, "Amount", amount);
return doc.OuterXml;
}
private static void InsertDataNode(XmlDocument doc, XmlElement parentElem, string nodeName, string nodeValue)
{
XmlElement elem = doc.CreateElement(nodeName);
elem.InnerText = nodeValue;
parentElem.AppendChild(elem);
}
and am getting the result as
<root>
<data>
<struct>
<PartnerCD>123</PartnerCD>
<UserName>api</UserName>
<Password>pass</Password>
<Action>token</Action>
<Token>4847898</Token>
<Products>
<Product>
<ProductID>123</ProductID>
<SVA>e8a8227c-bba3-4f32-a2cd-15e8f246344b</SVA>
<Amount>700</Amount>
</Product>
</Products>
</struct>
</data>
</root>
I want the PartnerCD and ProductId elements as integer and Amount element as decimal. I have tried XMLNodeType but no use.
Well the data type is irrelevant in the XML as such, it's all defined in the schema it uses, that's where the declaration of expected data types are stored.
So if you have a XSD that says that /root/data/struct/PartnerCD is of type xs:int then you will get validation errors upon validating the file. The XML itself is just a container of all data, it doesn't include the meta information. You CAN define it manually, but the Point is beyond me in about 99.99% of the cases, and it's more or less a bastard of XML, like MSXML that will understand what you're up to.
Xml has no concept of "data type" natively, the XmlNodeType you refer to is what type of Node it is (such as element, attribute etc), not what type of data is contained within it.
Personally I would create an object and Serialize\Deserialize to\from XML like so.....
using System;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.IO;
namespace _37321906
{
class Program
{
static void Main(string[] args)
{
Root root = new Root();
root.Data.Struct.PartnerCD = 123;
root.Data.Struct.UserName = "api";
root.Data.Struct.Password = "pass";
root.Data.Struct.Action = "token";
root.Data.Struct.Token = 4847898;
root.Data.Struct.Products.Product.Add(new Product { ProductID = 123, SVA = "e8a8227c-bba3-4f32-a2cd-15e8f246344b", Amount = 700.0001 });
// Serialize the root object to XML
Serialize<Root>(root);
// Deserialize from XML
Root DeserializeRoot = Deserialize<Root>();
}
private static void Serialize<T>(T data)
{
// Use a file stream here.
using (TextWriter WriteFileStream = new StreamWriter("test.xml"))
{
// Construct a SoapFormatter and use it
// to serialize the data to the stream.
XmlSerializer SerializerObj = new XmlSerializer(typeof(T));
try
{
// Serialize EmployeeList to the file stream
SerializerObj.Serialize(WriteFileStream, data);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("Failed to serialize. Reason: {0}", ex.Message));
}
}
}
private static T Deserialize<T>() where T : new()
{
//List<Employee> EmployeeList2 = new List<Employee>();
// Create an instance of T
T ReturnListOfT = CreateInstance<T>();
// Create a new file stream for reading the XML file
using (FileStream ReadFileStream = new FileStream("test.xml", FileMode.Open, FileAccess.Read, FileShare.Read))
{
// Construct a XmlSerializer and use it
// to serialize the data from the stream.
XmlSerializer SerializerObj = new XmlSerializer(typeof(T));
try
{
// Deserialize the hashtable from the file
ReturnListOfT = (T)SerializerObj.Deserialize(ReadFileStream);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("Failed to serialize. Reason: {0}", ex.Message));
}
}
// return the Deserialized data.
return ReturnListOfT;
}
// function to create instance of T
public static T CreateInstance<T>() where T : new()
{
return (T)Activator.CreateInstance(typeof(T));
}
}
[XmlRoot(ElementName = "Product")]
public class Product
{
[XmlElement(ElementName = "ProductID")]
public int ProductID { get; set; }
[XmlElement(ElementName = "SVA")]
public string SVA { get; set; }
[XmlElement(ElementName = "Amount")]
public double Amount { get; set; }
}
[XmlRoot(ElementName = "Products")]
public class Products
{
public Products()
{
this.Product = new List<Product>();
}
[XmlElement(ElementName = "Product")]
public List<Product> Product { get; set; }
}
[XmlRoot(ElementName = "struct")]
public class Struct
{
public Struct()
{
this.Products = new Products();
}
[XmlElement(ElementName = "PartnerCD")]
public int PartnerCD { get; set; }
[XmlElement(ElementName = "UserName")]
public string UserName { get; set; }
[XmlElement(ElementName = "Password")]
public string Password { get; set; }
[XmlElement(ElementName = "Action")]
public string Action { get; set; }
[XmlElement(ElementName = "OfficeCD")]
public string OfficeCD { get; set; }
[XmlElement(ElementName = "ChannelCD")]
public string ChannelCD { get; set; }
[XmlElement(ElementName = "Token")]
public int Token { get; set; }
[XmlElement(ElementName = "Notes")]
public string Notes { get; set; }
[XmlElement(ElementName = "Products")]
public Products Products { get; set; }
}
[XmlRoot(ElementName = "data")]
public class Data
{
public Data()
{
this.Struct = new Struct();
}
[XmlElement(ElementName = "struct")]
public Struct Struct { get; set; }
}
[XmlRoot(ElementName = "root")]
public class Root
{
public Root()
{
this.Data = new Data();
}
[XmlElement(ElementName = "data")]
public Data Data { get; set; }
}
}
find your XML in the build folder called test.xml

Add schemaLocation to XML serializing List<T> using XmlSerializer

I'm trying to add schemaLocation attribute to XML root element when serializing List<T>. Code works fine if I'm serializing just one object but does not work on lists. My current code:
public class SomeObject
{
public int Id { get; set; }
public string Name { get; set; }
}
public class XmlListContainer<T> : List<T>
{
[XmlAttribute(Namespace = XmlSchema.InstanceNamespace)]
public string schemaLocation = "http :// localhost/someschema";
}
public class BuildXml
{
public static void GetXml()
{
var list = new XmlListContainer<SomeObject>()
{
new SomeObject() { Id = 1, Name = "One" },
new SomeObject() { Id = 2, Name = "Two" },
};
var objectToXml = list;
string output;
using (var writer = new StringWriter())
{
var xs = new XmlSerializer(objectToXml.GetType());
var nameSpaces = new XmlSerializerNamespaces();
nameSpaces.Add("xsi", "http :// www.w3.org/2001/XMLSchema-instance");
xs.Serialize(writer, objectToXml, nameSpaces);
output = writer.GetStringBuilder().ToString();
writer.Close();
}
Console.WriteLine(output);
}
}
XML root element appears without schemaLocation:
<ArrayOfSomeObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
If I'm changing code to
public class SomeObject
{
public int Id { get; set; }
public string Name { get; set; }
[XmlAttribute(Namespace = XmlSchema.InstanceNamespace)]
public string schemaLocation = "http :// localhost/someschema";
}
...
var objectToXml = new SomeObject() { Id = 1, Name = "One" };
...all looks fine but I need list list
<SingleObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://localhost/someschema">
Is it possible to add schemaLocation attribute when serializing List<T>?

Problems deserializing List of objects

I am having trouble deserializing a list of objects. I can get just one object to serialize into an object but cannot get the list. I get no error it just returns an empty List. This is the XML that gets returned:
<locations>
<location locationtype="building" locationtypeid="1">
<id>1</id>
<name>Building Name</name>
<description>Description of Building</description>
</location>
</locations>
This is the class I have and I am deserializing in the GetAll method:
[Serializable()]
[XmlRoot("location")]
public class Building
{
private string method;
[XmlElement("id")]
public int LocationID { get; set; }
[XmlElement("name")]
public string Name { get; set; }
[XmlElement("description")]
public string Description { get; set; }
[XmlElement("mubuildingid")]
public string MUBuildingID { get; set; }
public List<Building> GetAll()
{
var listBuildings = new List<Building>();
var building = new Building();
var request = WebRequest.Create(method) as HttpWebRequest;
var response = request.GetResponse() as HttpWebResponse;
var streamReader = new StreamReader(response.GetResponseStream());
TextReader reader = streamReader;
var serializer = new XmlSerializer(typeof(List<Building>),
new XmlRootAttribute() { ElementName = "locations" });
listBuildings = (List<Building>)serializer.Deserialize(reader);
return listBuildings;
}
}
Try this:
[XmlRoot("locations")]
public class BuildingList
{
public BuildingList() {Items = new List<Building>();}
[XmlElement("location")]
public List<Building> Items {get;set;}
}
Then deserialize the whole BuildingList object.
var xmlSerializer = new XmlSerializer(typeof(BuildingList));
var list = (BuildingList)xmlSerializer.Deserialize(xml);
I know this is an old(er) question, but I struggled with this today, and found an answer that doesn't require encapsulation.
Assumption 1: You have control over the source Xml and how it is constructed.
Assumption 2: You are trying to serialise the Xml directly into a List<T> object
You must name the Root element in the Xml as ArrayOfxxx where xxx is the name of your class (or the name specified in XmlType (see 2.))
If you wish your xml Elements to have a different name to the class, you should use XmlType on the class.
NB: If your Type name (or class name) starts with a lowercase letter, you should convert the first character to uppercase.
Example 1 - Without XmlType
class Program
{
static void Main(string[] args)
{
//String containing the xml array of items.
string xml =
#"<ArrayOfItem>
<Item>
<Name>John Doe</Name>
</Item>
<Item>
<Name>Martha Stewart</Name>
</Item>
</ArrayOfItem>";
List<Item> items = null;
using (var mem = new MemoryStream(Encoding.Default.GetBytes(xml)))
using (var stream = new StreamReader(mem))
{
var ser = new XmlSerializer(typeof(List<Item>)); //Deserialising to List<Item>
items = (List<Item>)ser.Deserialize(stream);
}
if (items != null)
{
items.ForEach(I => Console.WriteLine(I.Name));
}
else
Console.WriteLine("No Items Deserialised");
}
}
public class Item
{
public string Name { get; set; }
}
Example 2 - With XmlType
class Program
{
static void Main(string[] args)
{
//String containing the xml array of items.
//Note the Array Name, and the Title case on stq.
string xml =
#"<ArrayOfStq>
<stq>
<Name>John Doe</Name>
</stq>
<stq>
<Name>Martha Stewart</Name>
</stq>
</ArrayOfStq>";
List<Item> items = null;
using (var mem = new MemoryStream(Encoding.Default.GetBytes(xml)))
using (var stream = new StreamReader(mem))
{
var ser = new XmlSerializer(typeof(List<Item>)); //Deserialising to List<Item>
items = (List<Item>)ser.Deserialize(stream);
}
if (items != null)
{
items.ForEach(I => Console.WriteLine(I.Name));
}
else
Console.WriteLine("No Items Deserialised");
}
}
[XmlType("stq")]
public class Item
{
public string Name { get; set; }
}
Not sure how Building corresponds with the location you have in your xml, but to me it makes more sense if they're named equivalently. Instead of using a List use a LocationList, and it becomes:
[Serializable()]
[XmlRoot("locations")]
public class LocationCollection{
[XmlElement("location")]
public Location[] Locations {get;set;}
}
[Serializable()]
[XmlRoot("location")]
public class Location
{
[XmlElement("id")]
public int LocationID { get; set; }
[XmlAttribute("locationtype")]
public string LocationType {get;set;}
[XmlElement("name")]
public string Name { get; set; }
[XmlElement("description")]
public string Description { get; set; }
[XmlElement("mubuildingid")]
public string MUBuildingID { get; set; }
}
You can then deserialize as follows:
var request = WebRequest.Create(method) as HttpWebRequest;
var response = request.GetResponse() as HttpWebResponse;
var streamReader = new StreamReader(response.GetResponseStream());
TextReader reader = streamReader;
var serializer = new XmlSerializer(typeof(LocationCollection),
new XmlRootAttribute() { ElementName = "locations" });
var listBuildings = (LocationCollection)serializer.Deserialize(reader);
return listBuildings;
I know, old question, but came across it when faced by a similar issue.
Building on #ricovox's answer and in context of the OP's question, this is the model I would use to serialize his xml:
[Serializable, XmlRoot("locations")]
public class BuildingList
{
[XmlArrayItem("location", typeof(Building))]
public List<Building> locations { get; set; }
}
[Serializable]
public class Building
{
public int LocationID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string MUBuildingID { get; set; }
public List<Building> GetAll()
{
...
}
}
The OP's mistake was to create the list item as the root
Use [XMLArray] for collection properties.

Categories