C# XML parsing thru EPPlus - c#

I am parsing XML, I have generated Class from XSD file, I am able to access simple values from XML, but I don't know how to get value from this. I need it as String.
public partial class AccountIdentification4Choice {
private object itemField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("IBAN", typeof(string))]
[System.Xml.Serialization.XmlElementAttribute("Othr", typeof(GenericAccountIdentification1))]
public object Item {
get {
return this.itemField;
}
set {
this.itemField = value;
}
}
}
In XML value can be like this:
<CdtrAcct><Id><Othr><Id>BBAN</Id></Othr></Id></CdtrAcct>
or
<CdtrAcct><Id><IBAN>BBAN</IBAN></Id></CdtrAcct>
Update - all resource files:
XML: Priklad_multi.XML
XSD: camt.053.001.02.xsd
Then I parse XML with EPPlus package:
XmlSerializer ser = new XmlSerializer(typeof(Document));
Document resp = ser.Deserialize(new FileStream(file, FileMode.Open)) as Document;
And then I can access XML values like this (for example Stmt-Acct)
resp.BkToCstmrStmt.Stmt[ind].Acct.Id.Item
But I don't know how to access this CdtrAcct section in same way.

Your question is not clear, but as I understand you want to get IBAN tag, right? If so, you could do that easily with Linq To XML. ie:
void Main()
{
string xml1 = "<CdtrAcct><Id><Othr><Id>BBAN</Id></Othr></Id></CdtrAcct>";
string xml2 = "<CdtrAcct><Id><IBAN>BBAN</IBAN></Id></CdtrAcct>";
Console.WriteLine(CheckIban(xml1));
Console.WriteLine(CheckIban(xml2));
}
private string CheckIban(string xml)
{
var iban = XElement.Parse(xml).DescendantsAndSelf("IBAN").FirstOrDefault();
if (iban != null)
{
return (string)iban;
}
iban = XElement.Parse(xml).DescendantsAndSelf("Othr")
.FirstOrDefault();
if (iban != null)
{
return iban.Element("Id").Value;
}
return null;
}

Related

Serialize c# object in XML using variable content as attribute name

I have the following c# object:
class Modification {
public string Name;
public string Value;
}
I want to use the serializer to serialize my object the following way:
<name>value</name>
Example: Let's say we set those variables to
Name = "Autoroute"
Value = 53
I want the xml to look like:
<test>
<Autoroute>53</Autoroute>
</test>
I saw somewhere that this feature is not supported by the serializer, but is there a way to overload the serializer to allow this kind of behavior ?
Changing the XML structure is not an option since it is already a convention.
You can use IXmlSerializable to do this, though this doesn't give you control over the root element name - you have to set this in the serializer (which may present other challenges when you come to read it as part of a larger xml structure...).
public class Modification : IXmlSerializable
{
public string Name;
public string Value;
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
reader.ReadStartElement();
Name = reader.Name;
Value = reader.ReadElementContentAsString();
reader.ReadEndElement();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteElementString(Name, Value);
}
}
Usage,
Modification modification = new Modification()
{
Name = "Autoroute",
Value = "53"
};
Modification andBack = null;
string rootElement = "test";
XmlSerializer s = new XmlSerializer(typeof(Modification), new XmlRootAttribute(rootElement));
using (StreamWriter writer = new StreamWriter(#"c:\temp\output.xml"))
s.Serialize(writer, modification);
using (StreamReader reader = new StreamReader(#"c:\temp\output.xml"))
andBack = s.Deserialize(reader) as Modification;
Console.WriteLine("{0}={1}", andBack.Name, andBack.Value);
The XML produced by this looks like this,
<?xml version="1.0" encoding="utf-8"?>
<test>
<Autoroute>53</Autoroute>
</test>

Get node value of Parent two level up in XML in C#

I have XML as shown in sample below -
<?xml version="1.0" encoding="UTF-8"?>
<Model>
<Part Id="0">
<Specs>
<Spec Id = "100" name="SpecNode">
</Spec>
</Specs>
</Part>
</Model>
This is an sample illustration of XML I have , so pls ignore any typing errors.
So in this XML I was able to retrieve Spec as XPathNodeIterator object. So now I would like to go for Part node and get Id attribute value of it. for what I have is XPathNodeIterator object which points to Spec and Part node lies two level above.
So please guide me in code changes I shall do to achieve this requirement.
Her is my code snippet..
System.Xml.XPath.XPathDocument xmlDoc = new System.Xml.XPath.XPathDocument("my.xml");
XPathNavigator xmlNav = xmlDoc.CreateNavigator();
XPathNodeIterator nodes = xmlNav.Select(XPathExpression.Compile(#"//Part/Specs/Spec[#name="SpecNode"]))
Above code sample gives me nodes object. SO my requirement now is to get Id value of Part node which two level above it.
You could use the following LINQ to retrieve the Id-attribute of the Part-node:
const string file = #"D:\Temp\file.xml";
// Load the file.
XDocument doc = XDocument.Load(file);
// Retrieve the attribute selecting the Part-Element and then its Id-attribute.
XAttribute partAttribute = doc.Root.Descendants("Part").Select(element => element.Attribute("Id")).FirstOrDefault();
// Call partAttribute.Value to retrieve its' value.
Console.WriteLine(partAttribute.Value);
Console.Read();
Output: 0.
Do note that if the Part-Element does not exist, a NullReferenceException will be thrown on the partAttribute.Value call. The same happens if the Part-Element exists but the Id does not. Use if(partAttribute != null) to make sure if the value exists.
If you will be getting alot of Part-nodes, you could sort them on ID using KeyValuePairs:
List<KeyValuePair<int, XElement>> partNodesWithIDValue = new List<KeyValuePair<int, XElement>>();
// Get a list of all Part-nodes where an ID exists.
List<XElement> partNodes = doc.Root.Descendants("Part").Where(element => element.Attribute("Id") != null).ToList();
// Sort the XElements according to their ID-value.
foreach (XElement partNode in partNodes)
{
KeyValuePair<int, XElement> elementWithAttribID = new KeyValuePair<int, XElement>(int.Parse(partNode.Attribute("Id").Value), partNode);
partNodesWithIDValue.Add(elementWithAttribID);
}
// Get a list of all Part-elements where the ID = 1.
List<XElement> partNodesWithID1 = partNodesWithIDValue.Where(kvp => kvp.Key == 1).Select(kvp => kvp.Value).ToList();
Seeing as you want to keep your original code, a simple change of XPath does the trick:
XPathNodeIterator nodes = xmlNav.Select(XPathExpression.Compile(#"//Part[#Id]"));
//Part[#Id]: //Part selects all nodes that are named Part. Adding the [#Id] makes it only select those Part-nodes that have an Id-attribute.
Deserialize the XML to an object, it'll be easier to work with and produces cleaner code:
Model class:
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class Model
{
private ModelPart[] partField;
[System.Xml.Serialization.XmlElementAttribute("Part")]
public ModelPart[] Part
{
get
{
return this.partField;
}
set
{
this.partField = value;
}
}
}
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class ModelPart
{
private ModelPartSpecs specsField;
private byte idField;
public ModelPartSpecs Specs
{
get
{
return this.specsField;
}
set
{
this.specsField = value;
}
}
[System.Xml.Serialization.XmlAttributeAttribute()]
public byte Id
{
get
{
return this.idField;
}
set
{
this.idField = value;
}
}
}
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class ModelPartSpecs
{
private ModelPartSpecsSpec specField;
public ModelPartSpecsSpec Spec
{
get
{
return this.specField;
}
set
{
this.specField = value;
}
}
}
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class ModelPartSpecsSpec
{
private byte idField;
private string nameField;
[System.Xml.Serialization.XmlAttributeAttribute()]
public byte Id
{
get
{
return this.idField;
}
set
{
this.idField = value;
}
}
[System.Xml.Serialization.XmlAttributeAttribute()]
public string name
{
get
{
return this.nameField;
}
set
{
this.nameField = value;
}
}
}
Deserialization:
XmlSerializer serializer = new XmlSerializer(typeof(Model));
Model model = null;
using (XmlReader reader = XmlReader.Create("data.xml"))
{
model = (Model)serializer.Deserialize(reader);
}
Now you'll be able to access model as an object and accessing the Part node is as simple as doing:
model.Part

Serialization: How to Deserialize in C#

How can I deserialize the string based on what I have done in this method? Basically, what I have here is to pass the string through the network using serialization and deserialize the string in order to convey the message. But once I managed to receive the message, I have no idea if what I'm doing is correct. Here's the code:
string ConvertToString(FrogGame np, Frog1 pm, Frog2 pm2) //Serialization. the three parameters are the classes.
{
XmlSerializer sendSerializer = new XmlSerializer(typeof(FrogGame),new Type[]{typeof(Frog1),typeof(Frog2)});
StreamWriter myWriter = new StreamWriter(#"pad1.xml");
sendSerializer.Serialize(myWriter, np);
sendSerializer.Serialize(myWriter, pm);
sendSerializer.Serialize(myWriter, pm2);
return myWriter.ToString();
} //Overall, I serialize it into string
Once I pass the string through the network, I want to deserialize it in order the pass the message to the classes. How do I continue here onwards? How can I edit? The code:
void StringReceived(string str) //so str is myWriter.ToString()
{
XmlSerializer revSerializer = new XmlSerializer(typeof(FrogGame), new Type[] { typeof(Frog1), typeof(Frog2) });
FileStream myFileStream = new FileStream(#"pad1.xml", FileMode.Open);
FrogGame b = (FrogGame)revSerializer.Deserialize(myFileStream);
if (b is Frog1)
{
if (Network.IsServer())
{
pm = (Frog1)b;
pm.Position.Y = b.pm.Position.Y;
pm.Position.X = b.pm.Position.X;
}
else
{
System.Diagnostics.Debug.WriteLine("BAD Message: " + msg);
}
}
else if (b is Frog2)
{
if (Network.IsClient())
{
pm2 = (PaddleMessage2)b;
pm2.Position.Y = b.pm2.Position.Y;
pm2.Position.X = b.pm2.Position.X;
}
else
{
System.Diagnostics.Debug.WriteLine("BAD Message: " + msg);
}
}
}
I might misinterpret your problem, but I why don't you put all the thing you want to save in a class and do it like this (plus, if you use class, your data "transportation" and "management" will be much easier) :
SERIALIZATION
XmlSerializer serializer = new XmlSerializer(typeof(FrogGameData));
TextWriter textWriter = new StreamWriter("FrogGameSaveFile.xml");
serializer.Serialize(textWriter, _frogGameData);
textWriter.Close();
DESERIALIZATION
XmlSerializer deserializer = new XmlSerializer(typeof(FrogGameData));
TextReader textReader = new StreamReader("FrogGameSaveFile.xml");
_frogGameData = (FrogGameData)deserializer.Deserialize(textReader);
textReader.Close();
Note : The need-to-be-saved field should have property, because the tag in the XML will mimic the property name.
Additional Note : FrogGameData is not different than a normal class for automatic serialization like this. The XML will mimic your property order in the class for the one in the XML file.
But if you wanna need to rearrange the XML tag placement, you could do something like [XmlElement(Order = 1)],[XmlElement(Order = 2)], etc on top of your property to customize the order in XML file.
UPDATE
In case you need it, this is an example of your FrogGameData class :
public class FrogGameData
{
private Frog _frog1;
private Frog _frog2;
public Frog Frog1
{
get { return _frog1; }
set { _frog1 = value; }
}
public Frog Frog2
{
get { return _frog2; }
set { _frog2 = value; }
}
}
And the XML will pretty much like this :
<?xml version="1.0" encoding="utf-8"?>
<FrogGameData>
<Frog1>Something-depends-on-your-data</Frog1>
<Frog2>Something-depends-on-your-data</Frog2>
</FrogGameData>
But, if your class is (Note the XmlElement part) :
public class FrogGameData
{
private Frog _frog1;
private Frog _frog2;
[XmlElement(Order = 2)]
public Frog Frog1
{
get { return _frog1; }
set { _frog1 = value; }
}
[XmlElement(Order = 1)]
public Frog Frog2
{
get { return _frog2; }
set { _frog2 = value; }
}
}
Then, your XML will be :
<?xml version="1.0" encoding="utf-8"?>
<FrogGameData>
<Frog2>Something-depends-on-your-data</Frog2>
<Frog1>Something-depends-on-your-data</Frog1>
</FrogGameData>

Parse xml to object

I'm trying to convert my xml file to a list of objects.
private void ReadChangelog()
{
XmlSerializer serializer = new XmlSerializer(typeof(Changelog));
Changelog changelog = (Changelog)serializer.Deserialize(new StringReader("changelog.xml"));
foreach (Release release in changelog.Releases)
{
string version = release.Version;
string date = release.Date;
string changes = release.Changes;
}
}
This is my changelog class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
[XmlRoot()]
public class Changelog
{
private Release[] releases;
public Release[] Releases
{
get { return releases; }
set { releases = value; }
}
}
public class Release
{
private string version;
private string date;
private string changes;
[XmlAttribute]
public string Version
{
get { return version; }
set { version = value; }
}
[XmlAttribute]
public string Date
{
get { return date; }
set { date = value; }
}
[XmlAttribute]
public string Changes
{
get { return changes; }
set { changes = value; }
}
}
And this is my xml
<?xml version="1.0" encoding="utf-8" ?>
<Changelog>
<Releases>
<Release>
<Version>1511</Version>
<Date>25-11-2013</Date>
<Changes>
qzdqzdqzdqzdzdzzqefrsrgsrg
</Changes>
</Release>
<Release>
<Version>1510</Version>
<Date>25-11-2013</Date>
<Changes>
Blabqzdzqdqzdqzd
</Changes>
</Release>
<Release>
</Releases>
</Changelog>
But when I try to run this I get an error
InvalidOperationException, The xml document (1,1) contains an error.
What am I doing wrong?
new StringReader("changelog.xml") doesn't read in the contents of changelog.xml. Instead, this code leaves you trying to deserialize the literal 'changelog.xml' string. I think you want something like new StreamReader("changelog.xml").
StringReader creates stream from string content, not from the file with given path. User StreamReader instead.
Changelog changelog = (Changelog)serializer.Deserialize(new StreamReader("changelog.xml"));
Despite of that, there are couple more errors in your code:
Your document uses elements, and your class declaration uses XmlAttributeAttribute. It won't work together.
Your document is not a correct XML document. It has some elements that are not closed.

XMLSerializer not deserializing XML

I am receiving the following error trying to deserialize xml. This produces the error:
XmlSerializer serializer = new XmlSerializer(typeof(PrivateOptionsAPIResponse));
var result = serializer.Deserialize(streamReader);
Exception:
System.InvalidOperationException was caught
Message=There is an error in XML document (0, 0)
InnerException: System.Xml.XmlException
Message=Root element is missing
Source=System.Xml
I am not sure how to correct the problem. Request returns the following XML:
<PrivateOptionsAPIResponse>
<CountiesForPostalCodeResponse>
<Counties>
<County>
<CountyName>PRINCE WILLIAM</CountyName>
<StateCode>VA</StateCode>
</County>
<County>
<CountyName>MANASSAS CITY</CountyName>
<StateCode>VA</StateCode>
</County>
<County>
<CountyName>MANASSAS PARK CITY</CountyName>
<StateCode>VA</StateCode>
</County>
</Counties>
</CountiesForPostalCodeResponse>
</PrivateOptionsAPIResponse>
I used xsd.exe to generate a class. The definition on PrivateOptionsAPIResponse (generated by xsd.exe tool) shows:
public partial class PrivateOptionsAPIResponse {
private object itemField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("CountiesForPostalCodeResponse", typeof(ZipCodeValidationResponse))]
[System.Xml.Serialization.XmlElementAttribute("PlanDetailsForIndividualOrFamilyResponse", typeof(IndividualPlanBenefitResponse))]
[System.Xml.Serialization.XmlElementAttribute("PlansForIndividualOrFamilyResponse", typeof(IndividualPlanQuoteResponse))]
[System.Xml.Serialization.XmlElementAttribute("ProductDetailsForSmallGroupResponse", typeof(SmallGroupProductBenefitResponse))]
[System.Xml.Serialization.XmlElementAttribute("ProductsForSmallGroupResponse", typeof(SmallGroupProductQuoteResponse))]
public object Item {
get {
return this.itemField;
}
set {
this.itemField = value;
}
}
}
If I then browse to ZipCodeValidationResponse definition it shows this:
public partial class ZipCodeValidationResponse {
private CountyType[] countiesField;
/// <remarks/>
[System.Xml.Serialization.XmlArrayItemAttribute("County", IsNullable=false)]
public CountyType[] Counties {
get {
return this.countiesField;
}
set {
this.countiesField = value;
}
}
}
If I then browse definition on CountyType I see this:
public partial class CountyType {
private string countyNameField;
private StateAbbreviationType stateCodeField;
/// <remarks/>
public string CountyName {
get {
return this.countyNameField;
}
set {
this.countyNameField = value;
}
}
/// <remarks/>
public StateAbbreviationType StateCode {
get {
return this.stateCodeField;
}
set {
this.stateCodeField = value;
}
}
}
----------Working solution----------------:
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
string status = ((HttpWebResponse)response).StatusDescription;
if(status == "OK")
{
using (Stream responseStream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(responseStream))
{
var xmlSerializer = new XmlSerializer(typeof(PrivateOptionsAPIResponse));
var privateOptionsAPIResponse = xmlSerializer.Deserialize(reader) as PrivateOptionsAPIResponse;
}
}
}
}
How are you declaring your streamReader? Take a look at its contents and you'll most likely see it's empty or doesn't contain a complete XML document.
First, check whether your XML is in valid form. From the given exception, it seems you are supplying an invalid xml document. Much appreciate if you could post the content (xml) that you are trying to de serialize.

Categories

Resources