How do I deserialize this XML - c#

How correctly to deserialize XML from my example (look the question in the end)? Am I doing this right? Maybe there is a way to make it easier and more efficient?
XML:
<Warehouse>
<GUID>0d63057d-99e8-11e6-813b-0003ff000011</GUID>
<Name>WarehouseName</Name>
<Terms>
<Term TargetGUID="490ecabf-f011-11e3-b7d9-6c626dc1e098">2</Term>
<Term TargetGUID="f332d7ff-efd2-11e3-b7d9-6c626dc1e098">4</Term>
</Terms>
</Warehouse>
C#:
Warehouse.cs:
[Serializable]
public class Warehouse
{
[XmlArray("Terms", IsNullable=true)]
[XmlArrayItem("Term")]
public WarehouseTransferTerm[] TransferTerms { get; set; }
[XmlElement(ElementName="Name")]
public string InternalName { get; set; }
[XmlElement(ElementName="Guid")]
public Guid Guid { get; set; }
}
WarehouseTransferTerm.cs:
[Serializable]
public class WarehouseTransferTerm
{
public Guid SourceWarehouseGuid { get; set; }
[XmlAttribute(AttributeName = "TargetGUID")]
public Guid TargetWarehouseGuid { get; set; }
[XmlElement(ElementName="Term")]
public int TransferTermInDays { get; set; }
}
Question: How I can set Warehouse's GUID property value as SourceWarehouseGuid?

You could implement custom deserialization logic and just set the value on the dependent items. See here: https://learn.microsoft.com/en-us/dotnet/api/system.runtime.serialization.ondeserializedattribute?view=netframework-4.7.2
[OnDeserialized()]
internal void OnDeserializedMethod(StreamingContext context)
{
foreach(var term in TransferTerms)
{
term.TargetWarehouseGuid = this.Guid;
}
}

I like using Dictionaries along with Xml Linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
Dictionary<string, XElement> warehouses = doc.Descendants("Warehouse")
.GroupBy(x => (string)x.Element("GUID"), y => y)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
XElement warehouse = warehouses["0d63057d-99e8-11e6-813b-0003ff000011"];
Dictionary<string, XElement> terms = warehouse.Descendants("Term")
.GroupBy(x => (string)x.Attribute("TargetGUID"), y => y)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
string value = terms["490ecabf-f011-11e3-b7d9-6c626dc1e098"].Value;
warehouse.SetValue(value);
}
}
}

Related

How to deserialize this dictionary-like XML to Dictionary<string, TValue>?

I have the following materials.xml file:
<?xml version="1.0" encoding="utf-8" ?>
<dictionary>
<Sand>
<id>1000</id>
<name>Sand</name>
<state>Dust</state>
<color>#FAFAFAFF</color>
</Sand>
<Water>
<id>2000</id>
<name>Water</name>
<color>#1CA3EC64</color>
<state>Liquid</state>
</Water>
<Gas>
<color>#5F6A0032</color>
<id>3000</id>
<name>Gas</name>
<state>Gas</state>
</Gas>
</dictionary>
A single material is represented with the following class:
public class Material {
public readonly int id;
public readonly string name;
public Color color;
public MaterialState state;
}
I need a generic SerializableDictionary class that can be used like this:
var materials = new SerializableDictionary<Material>();
//...serialization stuff
materials["Rock"].color;
Is this achievable?
Use xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Drawing;
using System.Globalization;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
List<Material> materials = doc.Root.Elements()
.Select(x => new Material()
{
id = (int)x.Element("id"),
name = (string)x.Element("name"),
color = Color.FromArgb(int.Parse(((string)x.Element("color")).Substring(1), NumberStyles.HexNumber)),
state = (MaterialState)Enum.Parse(typeof(MaterialState),(string)x.Element("state"))
}).ToList();
Dictionary<string, Material> dict = materials
.GroupBy(x => x.name, y => y)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
}
}
public enum MaterialState
{
Dust,
Liquid,
Gas
}
public class Material
{
public int id { get;set; }
public string name { get;set;}
public Color color { get;set;}
public MaterialState state { get;set;}
}
}

Linq to XML complete Child Element XL structure

I'm trying to not use the old way of reading xml and give a try to linq to xml but I'm having a hard time to accomplish the following:
Response XML
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<PolicyResponse>
<serviceResponse>
<responseCode>0</responseCode>
<responseDescription>Success</responseDescription>
<responseDetail>Success</responseDetail>
<paging>
<pageNum>1</pageNum>
<pageSize>3</pageSize>
<totalRecords>3</totalRecords>
</paging>
</serviceResponse>
<detailsResponseList>
<detailResponse>
<policy>
<policySummaryInfo>
<PolicyNumber>1199128</PolicyNumber>
<PremiumChangeAmt>...</PremiumChangeAmt>
<WrittenAmt>...</WrittenAmt>
<PolicyStatusDesc>Expired</PolicyStatusDesc>
<BillingInfo>
<InsuredOrPrincipal>...</InsuredOrPrincipal>
</BillingInfo>
</policySummaryInfo>
</policy>
</detailResponse>
<detailResponse>
<policy>
<policySummaryInfo>
<PolicyNumber>1199128</PolicyNumber>
<PremiumChangeAmt>...</PremiumChangeAmt>
<WrittenAmt>...</WrittenAmt>
<PolicyStatusDesc>Active</PolicyStatusDesc>
<BillingInfo>
<InsuredOrPrincipal>...</InsuredOrPrincipal>
</BillingInfo>
</policySummaryInfo>
</policy>
</detailResponse>
</detailsResponseList>
</PolicyResponse>
</out2:getPolicySummaryResponse>
</soapenv:Body>
</soapenv:Envelope>
I'm doing this in C#
XDocument xdoc = new XDocument();
xdoc = XDocument.Parse(xmlResponse);
IEnumerable<XElement> items =
from el in xdoc.Descendants("detailResponse")
select el;
With this code I'm able to read bot detailReponse element but what I want is to keep only the XML detailResponse structure with the <PolicyStatusDesc></PolicyStatusDesc> equal to Active. Is that possible. I manage to gather specific data based on element names an so but how I can keep the whole XML child element structure (detailResponse element an its childs) by using Linq to XML.
Thanks
In your XML sample there in an invalid
</out2:getPolicySummaryResponse> tag which i have removed
Here is the code you may use for your result
IEnumerable<XElement> items =
from el in xdoc.Descendants("detailResponse")
where el.Element("policy")?.Element("policySummaryInfo")?.Element("PolicyStatusDesc")?.Value == "Active"
select el;
I often use code like below which gives a flatter results than using Serialization:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement xPolicyResponse = doc.Descendants("PolicyResponse").FirstOrDefault();
PolicyResponse policyResponse = new PolicyResponse(xPolicyResponse);
}
}
public class PolicyResponse
{
public ServiceResponse serviceResponse { get; set; }
public List<DetailResponse> detailResponse { get; set; }
public PolicyResponse() {}
public PolicyResponse(XElement element)
{
XElement xServiceResponse = element.Element("serviceResponse");
List<XElement> xdetailResponseList = element.Descendants("detailResponse").ToList();
serviceResponse = new ServiceResponse(xServiceResponse);
detailResponse = xdetailResponseList.Select(x => new DetailResponse(x)).ToList();
}
}
public class ServiceResponse
{
public int responseCode { get; set; }
public string responseDescription { get; set; }
public string responseDetail { get; set; }
public int pageNum { get; set; }
public int pageSize { get; set; }
public int totalRecords { get; set; }
public ServiceResponse() { }
public ServiceResponse(XElement element)
{
responseCode = (int)element.Element("responseCode");
responseDescription = (string)element.Element("responseDescription");
responseDetail = (string)element.Element("responseDetail");
pageNum = (int)element.Descendants("pageNum").FirstOrDefault();
pageSize = (int)element.Descendants("pageSize").FirstOrDefault();
totalRecords = (int)element.Descendants("totalRecords").FirstOrDefault();
}
}
public class DetailResponse
{
public string policyNumber { get; set; }
public string premiumChangeAmt { get; set; }
public string writtenAmt { get; set; }
public string policyStatusDesc { get; set; }
public string insuredOrPrincipal { get; set; }
public DetailResponse() { }
public DetailResponse(XElement element)
{
XElement xPolicySummaryInfo = element.Descendants("policySummaryInfo").FirstOrDefault();
policyNumber = (string)xPolicySummaryInfo.Element("PolicyNumber");
premiumChangeAmt = (string)xPolicySummaryInfo.Element("PremiumChangeAmt");
writtenAmt = (string)xPolicySummaryInfo.Element("WrittenAmt");
policyStatusDesc = (string)xPolicySummaryInfo.Element("PolicyStatusDesc");
insuredOrPrincipal = (string)xPolicySummaryInfo.Descendants("InsuredOrPrincipal").FirstOrDefault();
}
}
}
You can get the elements where <PolicyStatusDesc> has the value Active by filtering the <detailResponse> elements using el.Descendants("PolicyStatusDesc"), then selecting those elements having the value Active.
Using query syntax:
var items = from el in xdoc.Descendants("detailResponse")
where el.Descendants("PolicyStatusDesc").Any(p => p.Value == "Active")
select el;
Or using method syntax:
var items = xdoc.Descendants("detailResponse")
.Where(el => el.Descendants("PolicyStatusDesc")
.Any(p => p.Value == "Active"));

Deserializing XML Based on Element Attributes

I am trying to deserialize an XML file within a C# program that looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<Addresses>
<ListName>Flowers</ListName>
<Address contextRef="RP.CC">Some Address</Address>
<Address contextRef="RP.BE">Some Other Address</Address>
<Address contextRef="RP.BV">Yet Another Address</Address>
<Address contextRef="RP.CAL">Wow, I Can't Believe It's Another Address</Address>
</Addresses>
I do not have any control over the format of this file. But, it will always have some combination of these 4 Address elements (i.e. these 4 contextRef attribute values are the only ones used) with differing element values each time.
Now, instead of deserializing into an Address array, I need to send them to individual properties within an Addresses object. My Current implementation uses an array and then a setter method to set these properties based on the contextRef as so:
public class Addresses
{
[XmlElement("ListName")]
public string ListName { get; set; }
private Address[] _addresses;
[XmlElement("Address")]
public Address[] AddressesArray
{
get
{
return _addresses;
}
set
{
_addresses = value;
SetAddress();
}
}
[XmlIgnore]
public Address AddressG21 { get; set; }
[XmlIgnore]
public Address AddressG22 { get; set; }
[XmlIgnore]
public Address AddressG23 { get; set; }
[XmlIgnore]
public Address AddressG9 { get; set; }
private void SetAddress()
{
foreach (var address in _addresses)
{
if (address.ContextRef == "RP.CC")
{
AddressG21 = address;
}
else if (address.ContextRef == "RP.BE")
{
AddressG22 = address;
}
else if (address.ContextRef == "RP.BV")
{
AddressG23 = address;
}
else if (address.ContextRef == "RP.CAL")
{
AddressG9 = address;
}
}
}
}
Where the Address object is defined as so:
public class Address
{
private string valueField;
/// <remarks/>
[XmlText]
public string Value
{
get
{
return this.valueField;
}
set
{
this.valueField = value;
}
}
[XmlAttribute("contextRef")]
public string ContextRef { get; set; }
}
So, my question is, is there a neater/better way of deserializing this XML directly into the AddressG21, etc. object properties without first using the Address array?
Thanks in advance.
I would use xml linq and create a dictionary in the class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
Addresses addresses = doc.Descendants("Addresses").Select(x => new Addresses() {
ListName = (string)x.Element("ListName"),
dict = x.Elements("Address")
.GroupBy(y => (string)y.Attribute("contextRef"), z => (string)z)
.ToDictionary(y => y.Key, z => z.FirstOrDefault())
}).FirstOrDefault();
}
}
public class Addresses
{
public string ListName { get; set; }
public Dictionary<string, string> dict { get; set; }
}
}
If you had multiple Addresses elements then use this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
List<Addresses> addresses = doc.Descendants("Addresses").Select(x => new Addresses() {
ListName = (string)x.Element("ListName"),
dict = x.Elements("Address")
.GroupBy(y => (string)y.Attribute("contextRef"), z => (string)z)
.ToDictionary(y => y.Key, z => z.FirstOrDefault())
}).ToList();
}
}
public class Addresses
{
public string ListName { get; set; }
public Dictionary<string, string> dict { get; set; }
}
}

Deserialize XML into object structure including dictionary

I'm trying to deserialize a given XML File into an object structure.
This is the XML:
<StaticData>
<Configuration>
<SqlCmdParameters />
<Tables>
<Table Schema="dbo" Name="table1">
<Columns>
<Column Name="tab1col1" IsPrimaryKey="false" />
<Column Name="tab1col2" IsPrimaryKey="false" />
</Columns>
</Table>
<Table Schema="dbo" Name="table2">
<Columns>
<Column Name="tab2col1" IsPrimaryKey="false" />
<Column Name="tab2col2" IsPrimaryKey="false" />
</Columns>
</Table>
</Tables>
</Configuration>
<TableDataItems>
<TableData Schema="dbo" Name="table1">
<RowData tab1col1="11" tab1col2="text1" tab1col3="anotherText1" />
<RowData tab1col1="12" tab1col2="text2" tab1col3="anotherText2"/>
<RowData tab1col1="13" tab1col2="text3" tab1col3="anotherText3"/>
</TableData>
<TableData Schema="dbo" Name="table2">
<RowData tab2col1="22" tab2col2="text1" />
<RowData tab2col1="23" tab2col2="text1" />
<RowData tab2col1="24" tab2col2="text1" />
</TableData>
</TableDataItems>
</StaticData>
The classes I want to fill them in are:
[XmlRoot("StaticData")]
public class StaticData
{
[XmlElement("Configuration")]
public Configuration Configuration { get; set; }
[XmlElement("TableDataItems")]
public TableDataItems TableDataItems { get; set; }
}
public class Configuration
{
[XmlElement("Tables")]
public List<Table> Tables { get; set; }
[XmlElement("SqlCmdParameters")]
public List<SqlCommandParameter> SqlCommandParameters { get; set; }
}
public class TableDataItems
{
[XmlElement("TableData")]
public List<Table> TableDatas { get; set; }
}
public class Table
{
[XmlAttribute("Name")]
public string TableName { get; set; }
[XmlAttribute("Schema")]
public string SchemaName { get; set; }
[XmlElement("Columns")]
public List<Column> Columns { get; set; }
[XmlElement("RowData")]
public List<Row> Rows { get; set; }
public Table()
{
Columns = new List<Column>();
Rows = new List<Row>();
}
}
public class Column
{
[XmlAttribute("Name")]
public string Name { get; set; }
[XmlAttribute("IsPrimaryKey")]
public bool IsPrimaryKey { get; set; }
}
public class Row
{
public Row()
{
RowData = new Dictionary<string, string>();
}
???What Attribute should I put here???
public Dictionary<string, string> RowData { get; set; }
}
So, everything works fine until I get to the where all the Attributes should be filled into a dictionary.
This is how I deserialize the XML so far:
public void CreateObjectStructureFromXml()
{
using (TextReader textReader = new StringReader(XmlDocument.ToString()))
{
XmlSerializer serializer = new XmlSerializer(typeof(StaticData));
StaticData = (StaticData) serializer.Deserialize(textReader);
}
}
I get an exception as soon as I get to the Row elements.
Can anybody please point me to where I made the mistake or what I should do?
The XML RowData can come with a variable amount of attributes. The attributes are the content of a database table.
Thanks a lot in advance
Try xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
Table.tables = doc.Descendants("Table").Select(x => new Table() {
SchemaName = (string)x.Attribute("Schema"),
TableName = (string)x.Attribute("Name"),
Columns = x.Descendants("Column").Select(y => new Column()
{
Name = (string)y.Attribute("Name"),
IsPrimaryKey = (Boolean)y.Attribute("IsPrimaryKey")
}).ToList()
}).ToList();
Dictionary<string, XElement> tableData = doc.Descendants("TableData")
.GroupBy(x => (string)x.Attribute("Name"), y => y)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
foreach(Table table in Table.tables)
{
XElement xTable = tableData[table.TableName];
table.SchemaName = (string)xTable.Attribute("Schema");
table.Rows = xTable.Elements("RowData").Select(x => new Row() {
RowData = x.Attributes()
.GroupBy(y => y.Name.LocalName, z => (string)z)
.ToDictionary(y => y.Key, z => z.FirstOrDefault())
}).ToList();
}
}
}
public class Table
{
public static List<Table> tables = new List<Table>();
public string TableName { get; set; }
public string SchemaName { get; set; }
public List<Column> Columns { get; set; }
public List<Row> Rows { get; set; }
public Table()
{
Columns = new List<Column>();
Rows = new List<Row>();
}
}
public class Column
{
public string Name { get; set; }
public bool IsPrimaryKey { get; set; }
}
public class Row
{
public Dictionary<string, string> RowData { get; set; }
}
}

c# json rearrange with same value

How do u make the below json in c#
[
{"file": "fileName1", "key":0, title:"u1"},
{"file": "fileName1", "key":2, title:"u1"},
{"file": "fileName2", "key":5, title:"u1"},
{"file": "fileName2", "key":10, title:"u1"}
]
into this.
{
"fileName1" : [{"key":0, title:"u1"},{"key":2, title:"u1"}],
"fileName2" : [{"key":0, title:"u1"},{"key":2, title:"u1"}]
}
Thank you
I have done a .NEt fiddle for you requirement
https://dotnetfiddle.net/Wsnl9V
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
string input = #"[
{'file': 'fileName1', 'key':0, title:'u1'},
{'file': 'fileName1', 'key':2, title:'u1'},
{'file': 'fileName2', 'key':5, title:'u1'},
{'file': 'fileName2', 'key':10, title:'u1'}
]";
var existingList = JsonConvert.DeserializeObject<List<CurrentType>>(input);
var dictionary = new Dictionary<string,List<RequiredTypeFile>>();
var distinctFileNames = existingList.Select(x=> x.File).Distinct().ToList();
distinctFileNames.ForEach(x=>
{
var fileValue = existingList.Where(m=>m.File==x)
.Select(m => new RequiredTypeFile
{
Key = m.Key,
Title = m.Title
}).ToList();
dictionary.Add(x,fileValue);
});
var reqdJson = JsonConvert.SerializeObject(dictionary);
Console.WriteLine(reqdJson);
}
}
public class CurrentType
{
public string File
{
get;
set;
}
public int Key
{
get;
set;
}
public string Title
{
get;
set;
}
}
public class RequiredTypeFile
{
public int Key
{
get;
set;
}
public string Title
{
get;
set;
}
}

Categories

Resources