Parsing XML in C# with variable children structure - c#

I need to parse an XML file with the following structure: EDITED
…
<?xml version="1.0" encoding="windows-1252" ?>
<TABLE>
<COMPO>
<alim_code> 1000 </alim_code>
<const_code> 56700 </const_code>
<teneur> 0 </teneur>
<min missing=" " />
<max missing=" " />
<code_confiance> D </code_confiance>
<source_code missing="." />
</COMPO>
<COMPO>
<alim_code> 1000 </alim_code>
<const_code> 60000 </const_code>
<teneur> 37,5 </teneur>
<min> 37,3 </min>
<max> 37,6 </max>
<code_confiance> D </code_confiance>
<source_code> 38 </source_code>
</COMPO>
</TABLE>
…
As you can see several fields are described differently when the value is known or missing. I have tried to use ReadXml() in a DataSet but it does not seems to work on "variable structure".
Looks like the solution is probably to use Xdocument and LINQ but I am ignorant about LINQ and I did not succeed to write a working code.
I would appreciate if someone can show me possible code to parse and print (or even better add to a db) the content of this kind of XML file.

Linq will not be helpful here. What you can do is create the DTO for your xml using the sample xml that contains all the attributes and nodes which can be returned in the xml.
and then deserialize the xml in to that type.
Your classes would be something like following from the xml above which are being generated:
[XmlRoot(ElementName="min")]
public class Min {
[XmlAttribute(AttributeName="missing")]
public string Missing { get; set; }
}
[XmlRoot(ElementName="max")]
public class Max {
[XmlAttribute(AttributeName="missing")]
public string Missing { get; set; }
}
[XmlRoot(ElementName="source_code")]
public class Source_code {
[XmlAttribute(AttributeName="missing")]
public string Missing { get; set; }
}
[XmlRoot(ElementName="COMPO")]
public class COMPO {
[XmlElement(ElementName="alim_code")]
public string Alim_code { get; set; }
[XmlElement(ElementName="const_code")]
public string Const_code { get; set; }
[XmlElement(ElementName="teneur")]
public string Teneur { get; set; }
[XmlElement(ElementName="min")]
public Min Min { get; set; }
[XmlElement(ElementName="max")]
public Max Max { get; set; }
[XmlElement(ElementName="code_confiance")]
public string Code_confiance { get; set; }
[XmlElement(ElementName="source_code")]
public Source_code Source_code { get; set; }
}
Now you can use `XmlSerializer class to deserialize it :
XmlSerializer serializer = new XmlSerializer(typeof(List<COMPO>));
List<COMPO> compos = null;
using (var reader = new StringReader(xml))
{
compos = (List<COMPO>)serializer.Deserialize(reader);
}
EDIT:
In that case add another type for Table which would be :
[XmlRoot(ElementName="Table")]
public class Table {
[XmlElement(ElementName="COMPO")]
public List<COMPO> COMPO { get; set; }
}
and now the adjust the de-serialization code accordingly:
XmlSerializer serializer = new XmlSerializer(typeof(Table));
Table table = null;
using (var reader = new StringReader(xml))
{
compos = (Table)serializer.Deserialize(reader);
}

I would use Xml Linq. There are some items that can be null that you need to handle properly. See code below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Globalization;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
IFormatProvider provider = CultureInfo.InvariantCulture;
List<Compo> compos = doc.Descendants("COMPO").Select(x => new Compo() {
alim_code = (int?)x.Element("alim_code"),
const_code = (int?)x.Element("const_code"),
teneur = (string)x.Element("teneur") == "" ? null : (decimal?)Convert.ToDecimal((string) x.Element("teneur"),provider),
min = (string)x.Element("min") == "" ? null : (decimal?)Convert.ToDecimal((string) x.Element("teneur"),provider),
max = (string)x.Element("max") == "" ? null : (decimal?)Convert.ToDecimal((string) x.Element("teneur"),provider),
code_confiance = (string)x.Element("code_confiance"),
source_code = (string)x.Element("source_code") == "" ? null : (int?)int.Parse(((string)x.Element("source_code")).Trim())
}).ToList();
}
}
public class Compo
{
public int? alim_code {get; set;}
public int? const_code {get; set;}
public decimal? teneur {get; set;}
public decimal? min {get; set;}
public decimal? max {get; set;}
public string code_confiance {get; set;}
public int? source_code { get; set; }
}
}

Working solution based on Ehsan-Sajjad proposal :)
[XmlRoot(ElementName = "min")]
public class Min
{
[XmlAttribute(AttributeName = "missing")]
public string Missing { get; set; }
[XmlText]
public string Value { get; set; }
}
[XmlRoot(ElementName = "max")]
public class Max
{
[XmlAttribute(AttributeName = "missing")]
public string Missing { get; set; }
[XmlText]
public string Value { get; set; }
}
[XmlRoot(ElementName = "source_code")]
public class Source_code
{
[XmlAttribute(AttributeName = "missing")]
public string Missing { get; set; }
[XmlText]
public string Value { get; set; }
}
[XmlRoot(ElementName = "COMPO")]
public class COMPO
{
[XmlElement(ElementName = "alim_code")]
public string Alim_code { get; set; }
[XmlElement(ElementName = "const_code")]
public string Const_code { get; set; }
[XmlElement(ElementName = "teneur")]
public string Teneur { get; set; }
[XmlElement(ElementName = "min")]
public Min Min { get; set; }
[XmlElement(ElementName = "max")]
public Max Max { get; set; }
[XmlElement(ElementName = "code_confiance")]
public string Code_confiance { get; set; }
[XmlElement(ElementName = "source_code")]
public Source_code Source_code { get; set; }
}
[XmlRoot(ElementName = "TABLE")]
public class TABLE
{
[XmlElement(ElementName = "COMPO")]
public List<COMPO> COMPO { get; set; }
}
private void ReadCompoWithSerializer()
{
string xmlFile = "test.xml";
string xml = File.ReadAllText(xmlFile);
XmlSerializer serializer = new XmlSerializer(typeof(TABLE));
TABLE table = null;
using (var reader = new StringReader(xml))
{
table = (TABLE)serializer.Deserialize(reader);
}
}
Inside Min/Max/Source_code objects Value contains the value when present (in that case Missing is null) otherwise Value is null (in that case Missing contain a string)
Working solution based on jdweng proposal
public class Compo {
public string alim_code { get; set; }
public string const_code { get; set; }
public string teneur { get; set; }
public string min { get; set; }
public string max { get; set; }
public string code_confiance { get; set; }
public string source_code { get; set; }
}
private void ReadCompoWithLinq() {
const string FILENAME = "test.xml";
XDocument doc = XDocument.Load(FILENAME);
List<Compo> compos = doc.Descendants("COMPO").Select(x => new Compo()
{
alim_code = (string)x.Element("alim_code"),
const_code = (string)x.Element("const_code"),
teneur = (string)x.Element("teneur"),
min = (x.Element("min").Attribute("missing") != null) ? null : (string)x.Element("min"),
max = (x.Element("max").Attribute("missing") != null) ? null : (string)x.Element("max"),
code_confiance = (string)x.Element("code_confiance"),
source_code = (x.Element("source_code").Attribute("missing") != null) ? null : (string)x.Element("source_code"),
}).ToList();
}
The min,max,source_code objects contains the string value when provided (in that case the attribute "missing is used in XML description) otherwise the string value is null.

Related

InvalidOperationException when deserializing custom XML (lack of namespace)

I have an XML document that starts with the following root:
<?xml version="1.0" encoding="UTF-8"?>
<JPK
xmlns="http://jpk.mf.gov.pl/wzor/2019/09/27/09271/"
xmlns:etd="http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2018/08/24/eD/DefinicjeTypy/">
<Naglowek>
<KodFormularza kodSystemowy="SomeCode" wersjaSchemy="1-0">SomeCode</KodFormularza>
<WariantFormularza>3</WariantFormularza>
<CelZlozenia>1</CelZlozenia>
<DataWytworzeniaJPK>2021-06-30T15:57:53</DataWytworzeniaJPK>
<DataOd>2021-05-01</DataOd>
<DataDo>2021-05-31</DataDo>
<KodUrzedu>0000</KodUrzedu>
</Naglowek>
<Podmiot1>
<IdentyfikatorPodmiotu>
<etd:NIP>111111</etd:NIP>
<etd:PelnaNazwa>SomeName</etd:PelnaNazwa>
</IdentyfikatorPodmiotu>
<AdresPodmiotu>
<etd:Wojewodztwo>voivodeship</etd:Wojewodztwo>
<etd:KodKraju>PL</etd:KodKraju>
<etd:Powiat>Danzig</etd:Powiat>
<etd:Gmina>Danzig</etd:Gmina>
<etd:Ulica>SomeStreet</etd:Ulica>
<etd:NrDomu>81</etd:NrDomu>
<etd:NrLokalu>1</etd:NrLokalu>
<etd:Miejscowosc>Danzig</etd:Miejscowosc>
<etd:KodPocztowy>10-101</etd:KodPocztowy>
</AdresPodmiotu>
</Podmiot1>
<!-- These can be many in the same element, there's no root for this list -->
<Faktura>
<KodWaluty>PLN</KodWaluty>
<P_1>2021-05-04</P_1>
<P_2A>11 / 1111</P_2A>
<P_3A>Some Company</P_3A>
<P_3B>Some Address</P_3B>
<P_3C>Some Name</P_3C>
<P_3D>Some Other Address</P_3D>
<P_4B>Phone1</P_4B>
<P_5B>Phone2</P_5B>
<P_13_1>1.00</P_13_1>
<P_14_1>1.25</P_14_1>
<P_15>SomeDecimalNumber</P_15>
<P_16>false</P_16>
<P_17>false</P_17>
<P_18>false</P_18>
<P_18A>false</P_18A>
<P_19>false</P_19>
<P_20>false</P_20>
<P_21>false</P_21>
<P_22>false</P_22>
<P_23>false</P_23>
<P_106E_2>false</P_106E_2>
<P_106E_3>false</P_106E_3>
<RodzajFaktury>InvoiceType</RodzajFaktury>
</Faktura>
<!-- These can be many in the same element, there's no root for this list -->
<FakturaCtrl>
<LiczbaFaktur>1</LiczbaFaktur>
<WartoscFaktur>2.00</WartoscFaktur>
</FakturaCtrl>
<!-- These can be many in the same element, there's no root for this list -->
<FakturaWiersz>
<P_2B>04/123</P_2B>
<P_7>Text</P_7>
<P_8B>1.000000</P_8B>
<P_9A>7.00</P_9A>
<P_11>7.00</P_11>
<P_12>11</P_12>
</FakturaWiersz>
<FakturaWierszCtrl>
<LiczbaWierszyFaktur>11</LiczbaWierszyFaktur>
<WartoscWierszyFaktur>11.2</WartoscWierszyFaktur>
</FakturaWierszCtrl>
</JPK>
It has capital letters. I have no influence on its definition, I need to adjust myself.
I've written a class for it:
[XmlRoot(ElementName = "JPK", Namespace = "http://jpk.mf.gov.pl/wzor/2019/09/27/09271/", IsNullable = false)]
public class Jpk
{
public Jpk() { }
[XmlElement(ElementName = "Naglowek")]
public JpkHeader Header { get; set; }
[XmlElement(ElementName = "Podmiot1")]
public JpkSubject Subject { get; set; }
[XmlElement(ElementName = "Faktura")]
public JpkInvoice[] Invoices { get; set; }
[XmlElement(ElementName = "FakturaCtrl")]
public JpkInvoiceControl[] InvoiceControls { get; set; }
[XmlElement(ElementName = "FakturaWiersz")]
public JpkInvoiceRow[] InvoiceRows { get; set; }
[XmlElement(ElementName = "FakturaWierszCtrl")]
public JpkInvoiceRowControl InvoiceRowControl { get; set; }
}
public class JpkHeader
{
[XmlElement(ElementName = "KodFormularza")]
public string FormCode { get; set; }
[XmlElement(ElementName = "WariantFormularza")]
public string Variant { get; set; }
[XmlElement(ElementName = "CelZlozenia")]
public int Purpose { get; set; }
[XmlElement(ElementName = "DataWytworzeniaJPK")]
public DateTime CreationDate { get; set; }
[XmlElement(ElementName = "DataOd")]
public DateTime DateFrom { get; set; }
[XmlElement(ElementName = "DataDo")]
public DateTime DateTo { get; set; }
[XmlElement(ElementName = "KodUrzedu")]
public string OfficeCode { get; set; }
}
public class JpkInvoice
{
[XmlElement(ElementName = "KodWaluty")]
public string CurrencyCode { get; set; }
public DateTime P_1 { get; set; }
public string P_2A { get; set; }
public string P_3A { get; set; }
public string P_3B { get; set; }
public string P_3C { get; set; }
public string P_3D { get; set; }
public string P_4B { get; set; }
public string P_5B { get; set; }
public decimal P_13_1 { get; set; }
public decimal P_14_1 { get; set; }
public decimal P_15 { get; set; }
public bool P_16 { get; set; }
public bool P_17 { get; set; }
public bool P_18 { get; set; }
public bool P_18A { get; set; }
public bool P_19 { get; set; }
public bool P_20 { get; set; }
public bool P_21 { get; set; }
public bool P_22 { get; set; }
public bool P_23 { get; set; }
public bool P_106E_2 { get; set; }
public bool P_106E_3 { get; set; }
[XmlElement(ElementName = "RodzajFaktury")]
public string InvoiceType { get; set; }
}
public class JpkInvoiceControl
{
[XmlElement(ElementName = "LiczbaFaktur")]
public int InvoiceAmount { get; set; }
[XmlElement(ElementName = "WartoscFaktur")]
public decimal InvoiceValue { get; set; }
}
public class JpkInvoiceRow
{
public string P_2B { get; set; }
public string P_7 { get; set; }
public double P_8B { get; set; }
public decimal P_9A { get; set; }
public decimal P_11 { get; set; }
public int P_12 { get; set; }
}
public class JpkInvoiceRowControl
{
[XmlElement(ElementName = "LiczbaWierszyFaktur")]
public int InvoiceRowAmount { get; set; }
[XmlElement(ElementName = "WartoscWierszyFaktur")]
public decimal InvoiceRowSum { get; set; }
}
public class JpkSubject
{
[XmlElement(ElementName = "IdentyfikatorPodmiotu")]
public SubjectID SubjectId { get; set; }
[XmlElement(ElementName = "AdresPodmiotu")]
public SubjectAddress Address { get; set; }
}
public class SubjectID
{
[XmlElement(ElementName = "etd:NIP")]
public string NIP { get; set; }
[XmlElement(ElementName = "etd:PelnaNazwa")]
public string FullName { get; set; }
}
public class SubjectAddress
{
[XmlElement(ElementName = "etd:KodKraju")]
public string CountryCode { get; set; }
[XmlElement(ElementName = "etd:Wojewodztwo")]
public string Province { get; set; }
[XmlElement(ElementName = "etd:Powiat")]
public string District { get; set; }
[XmlElement(ElementName = "etd:Gmina")]
public string Community { get; set; }
[XmlElement(ElementName = "etd:Ulica")]
public string StreetName { get; set; }
[XmlElement(ElementName = "etd:NrDomu")]
public int HouseNumber { get; set; }
[XmlElement(ElementName = "etd:NrLokalu")]
public int FlatNumber { get; set; }
[XmlElement(ElementName = "etd:Miejscowosc")]
public string City { get; set; }
[XmlElement(ElementName = "etd:KodPocztowy")]
public string PostalCode { get; set; }
}
And I have my code that deserializes it:
var serializer = new XmlSerializer(typeof(Etc), new XmlRootAttribute("JPK"));
var streamReader = new StreamReader(#"C:\_NotInGit\sample.xml");
var smth = (Jpk)serializer.Deserialize(streamReader);
When I run this code I get
System.InvalidOperationException: 'There is an error in XML document (2, 2).'
InvalidOperationException: was not expected.
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
at System.Xml.Serialization.XmlSerializer.Deserialize(TextReader textReader)
at MyProject.Program.Main(String[] args) in C:\MyProject\Program.cs:line 15
I run my queries through the Internet:
I ensured that the XmlRoot element has the exact capitalized version I encounter in the file
I put the namespace in
I tried adding Serializable, no changes
I ensured I pass the XmlRootAttribute to the serializer constructor
My spider-sense tells me it might have to do with the second definition, but I'm not sure how to approach it. I tried to remove it (for science purposes), but it did not change the response.
Is there anything else I am missing?
Spoiler alert: It was (also) about the second namespace definition. Thankfully the accepted answer showed me how to declare it, and what to do with the etd part. That, and the removal of new XmlRootAttribute("JPK") from code.
When attempting to debug a XML deserialization issue, I find it helpful to serialize the class that I've created using some sample data. Then, I check if the data that I serialized (saved to a XML file) is the same as the XML file that I'm trying to deserialize.
In the XML data you posted, within Faktura, is the following:
<P_15>SomeDecimalNumber</P_15>
Then in class JpkInvoice is the following:
public decimal P_15 { get; set; }
This is an issue because the value in the XML file is a string, whereas the property is declared as decimal. Either the property data type needs to be string or the value in the XML file needs to be changed to a valid decimal value. For testing, in the XML, I replaced <P_15>SomeDecimalNumber</P_15> with <P_15>0</P_15>.
I've tested the following code with the XML that you provided - with the XML data modification described above. I changed the property names to match what's in the XML file as I find it easier that way. You can rename them if you like. Also, I prefer to use List instead of an array, so you'll notice that in the code as well.
In the code below, the following using statements are necessary:
using System.Collections.Generic;
using System.Xml;
using System.Xml.Serialization;
Create a class (name: Jpk)
Class: Jpk
[XmlRoot(ElementName = "JPK", Namespace = "http://jpk.mf.gov.pl/wzor/2019/09/27/09271/", IsNullable = false)]
public class Jpk
{
[XmlElement(ElementName = "Naglowek")]
public JpkNaglowek Naglowek { get; set; } = new JpkNaglowek(); //Header
[XmlElement(ElementName = "Podmiot1")]
public JpkPodmiot1 Podmiot1 { get; set; } = new JpkPodmiot1(); //Subject
[XmlElement(ElementName = "Faktura")]
public List<JpkFaktura> Faktura { get; set; } = new List<JpkFaktura>(); //Invoices
[XmlElement(ElementName = "FakturaCtrl")]
public List<JpkFakturaCtrl> FakturaCtrl { get; set; } = new List<JpkFakturaCtrl>(); //InvoiceControls
[XmlElement(ElementName = "FakturaWiersz")]
public List<JpkFakturaWiersz> FakturaWiersz { get; set; } = new List<JpkFakturaWiersz>(); //InvoiceRows
[XmlElement(ElementName = "FakturaWierszCtrl")]
public List<JpkFakturaWierszCtrl> FakturaWierszCtrl { get; set; } = new List<JpkFakturaWierszCtrl>(); //InvoiceRowControl
}
Class: JpkFaktura
public class JpkFaktura
{
private string p_1 = string.Empty;
[XmlIgnore]
public DateTime P_1Dt { get; private set; } = DateTime.MinValue; //value of P_1 as DateTime
[XmlElement]
public string KodWaluty { get; set; }
[XmlElement]
public string P_1
{
get
{
return this.p_1;
}
set
{
this.p_1 = value;
//try to convert to DateTime
DateTime dt = DateTime.MinValue;
DateTime.TryParseExact(value, "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out dt);
//set value
this.P_1Dt = dt;
}
}
[XmlElement]
public string P_2A { get; set; }
[XmlElement]
public string P_3A { get; set; }
[XmlElement]
public string P_3B { get; set; }
[XmlElement]
public string P_3C { get; set; }
[XmlElement]
public string P_3D { get; set; }
[XmlElement]
public string P_4B { get; set; }
[XmlElement]
public string P_5B { get; set; }
[XmlElement]
public decimal P_13_1 { get; set; }
[XmlElement]
public decimal P_14_1 { get; set; }
[XmlElement]
public decimal P_15 { get; set; }
[XmlElement]
public bool P_16 { get; set; } = false;
[XmlElement]
public bool P_17 { get; set; } = false;
[XmlElement]
public bool P_18 { get; set; } = false;
[XmlElement]
public bool P_18A { get; set; } = false;
[XmlElement]
public bool P_19 { get; set; } = false;
[XmlElement]
public bool P_20 { get; set; } = false;
[XmlElement]
public bool P_21 { get; set; } = false;
[XmlElement]
public bool P_22 { get; set; } = false;
[XmlElement]
public bool P_23 { get; set; } = false;
[XmlElement]
public bool P_106E_2 { get; set; } = false;
[XmlElement]
public bool P_106E_3 { get; set; } = false;
[XmlElement]
public string RodzajFaktury { get; set; }
}
Note: In the code above you'll notice a property named P_1Dt. It's a public property that holds the value of P_1 as DateTime. By specifying [XmlIgnore] this property will be ignored during deserialization/serialization. In the XML, the format of the data is yyyy-MM-dd (ex: 2021-05-01), which is why it's necessary to specify the data type as a string. If the data type is specified as DateTime, when serialized the data in the XML file would look like yyyy-MM-ddTHH:mm:ss (ex: 2021-05-01T00:00:00)
Class: JpkFakturaCtrl
public class JpkFakturaCtrl
{
[XmlElement]
public decimal LiczbaFaktur { get; set; }
[XmlElement]
public decimal WartoscFaktur { get; set; }
}
Class: JpkFakturaWiersz
public class JpkFakturaWiersz
{
[XmlElement]
public string P_2B { get; set; }
[XmlElement]
public string P_7 { get; set; }
[XmlElement]
public decimal P_8B { get; set; }
[XmlElement]
public decimal P_9A { get; set; }
[XmlElement]
public decimal P_11 { get; set; }
[XmlElement]
public int P_12 { get; set; }
}
Class: JpkFakturaWierszCtrl
public class JpkFakturaWierszCtrl
{
[XmlElement]
public decimal LiczbaWierszyFaktur { get; set; }
[XmlElement]
public decimal WartoscWierszyFaktur { get; set; }
}
Class: JpkNaglowek
public class JpkNaglowek
{
private string dataOd = string.Empty;
private string dataDo = string.Empty;
[XmlIgnore]
public DateTime DataDoDt { get; private set; } //value of DataDo as DateTime
[XmlIgnore]
public DateTime DataOdDt { get; private set; } //value of DataDo as DateTime
[XmlElement(ElementName = "KodFormularza")]
public JpkNaglowekKodFormularza KodFormularza { get; set; } = new JpkNaglowekKodFormularza(); //FormCode
[XmlElement(ElementName = "WariantFormularza")]
public string WariantFormularza { get; set; } //Variant
[XmlElement(ElementName = "CelZlozenia")]
public int CelZlozenia { get; set; } //Purpose
[XmlElement(ElementName = "DataWytworzeniaJPK")]
public DateTime DataWytworzeniaJPK { get; set; } //CreationDate - DateTime
//DateFrom
[XmlElement(ElementName = "DataOd")]
public string DataOd
{
get
{
return this.dataOd;
}
set
{
this.dataOd = value;
//try to convert to DateTime
DateTime dt = DateTime.MinValue;
DateTime.TryParseExact(value, "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out dt);
//set value
this.DataOdDt = dt;
}
}
//DateTo
[XmlElement(ElementName = "DataDo")]
public string DataDo
{
get
{
return this.dataDo;
}
set
{
this.dataDo = value;
//try to convert to DateTime
DateTime dt = DateTime.MinValue;
DateTime.TryParseExact(value, "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out dt);
//set value
this.DataDoDt = dt;
}
}
[XmlElement(ElementName = "KodUrzedu")]
public string KodUrzedu { get; set; }
}
Note: In the code above you'll notice properties: DataDoDt and DataOdDt. They are public properties that hold the value of DataDo and DataOd respectively, as DateTime. By specifying [XmlIgnore] this property will be ignored during deserialization/serialization. In the XML, the format of the data is yyyy-MM-dd (ex: 2021-05-01), which is why it's necessary to specify the data type as a string. If the data type is specified as DateTime, when serialized the data in the XML file would look like yyyy-MM-ddTHH:mm:ss (ex: 2021-05-01T00:00:00)
Class: JpkNaglowekKodFormularza
public class JpkNaglowekKodFormularza
{
[XmlAttribute(AttributeName = "kodSystemowy")]
public string kodSystemowy { get; set; }
[XmlAttribute(AttributeName = "wersjaSchemy")]
public string wersjaSchemy { get; set; }
[XmlText]
public string Value { get; set; }
}
Class: JpkPodmiot1
public class JpkPodmiot1
{
[XmlElement(ElementName = "IdentyfikatorPodmiotu")]
public JpkPodmiot1IdentyfikatorPodmiotu IdentyfikatorPodmiotu { get; set; } = new JpkPodmiot1IdentyfikatorPodmiotu(); //SubjectId
[XmlElement(ElementName = "AdresPodmiotu")]
public JpkPodmiot1AdresPodmiotu AdresPodmiotu { get; set; } = new JpkPodmiot1AdresPodmiotu(); //Address
}
Class: JpkPodmiot1IdentyfikatorPodmiotu
[System.Xml.Serialization.XmlType(Namespace = "http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2018/08/24/eD/DefinicjeTypy/")]
public class JpkPodmiot1IdentyfikatorPodmiotu
{
[XmlElement(ElementName = "NIP")]
public string NIP { get; set; }
[XmlElement(ElementName = "PelnaNazwa")]
public string PelnaNazwa { get; set; } //FullName
}
In the code above, notice that the namespace was specified.
Class: JpkPodmiot1AdresPodmiotu
[System.Xml.Serialization.XmlType(Namespace = "http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2018/08/24/eD/DefinicjeTypy/")]
public class JpkPodmiot1AdresPodmiotu
{
[XmlElement(ElementName = "Wojewodztwo")]
public string Wojewodztwo { get; set; } //Province
[XmlElement(ElementName = "KodKraju")]
public string KodKraju { get; set; } //CountryCode
[XmlElement(ElementName = "Powiat")]
public string Powiat { get; set; } //District
[XmlElement(ElementName = "Gmina")]
public string Gmina { get; set; } //Community
[XmlElement(ElementName = "Ulica")]
public string Ulica { get; set; } //StreetName
[XmlElement(ElementName = "NrDomu")]
public Int32 NrDomu { get; set; } //HouseNumber
[XmlElement(ElementName = "NrLokalu")]
public Int32 NrLokalu { get; set; } //FlatNumber
[XmlElement(ElementName = "Miejscowosc")]
public string Miejscowosc { get; set; } //City
[XmlElement(ElementName = "KodPocztowy")]
public string KodPocztowy { get; set; } //PostalCode
}
In the code above, notice that the namespace was specified.
Here's a method that can be used to populate an instance of Jpk with some test data -- it's the data from the XML file that you specified above. It's useful for testing XML serialization.
CreateTestData
private Jpk CreateTestData()
{
Jpk jpk = new Jpk();
//Naglowek
jpk.Naglowek.KodFormularza.kodSystemowy = "SomeCode";
jpk.Naglowek.KodFormularza.wersjaSchemy = "1-0";
jpk.Naglowek.KodFormularza.Value = "SomeCode";
jpk.Naglowek.WariantFormularza = "3";
jpk.Naglowek.CelZlozenia = 1;
jpk.Naglowek.DataWytworzeniaJPK = DateTime.ParseExact("2021-06-30T15:57:53", "yyyy-MM-ddTHH:mm:ss", System.Globalization.CultureInfo.InvariantCulture); //"2021-06-30T15:57:53"; //ToDo: change to DateTime
jpk.Naglowek.DataOd = "2021-05-01";
jpk.Naglowek.DataDo = "2021-05-31";
jpk.Naglowek.KodUrzedu = "0000";
//Podmiot1
jpk.Podmiot1.IdentyfikatorPodmiotu.NIP = "111111";
jpk.Podmiot1.IdentyfikatorPodmiotu.PelnaNazwa = "SomeName";
jpk.Podmiot1.AdresPodmiotu.Wojewodztwo = "voivodeship";
jpk.Podmiot1.AdresPodmiotu.KodKraju = "PL";
jpk.Podmiot1.AdresPodmiotu.Powiat = "Danzig";
jpk.Podmiot1.AdresPodmiotu.Gmina = "Danzig";
jpk.Podmiot1.AdresPodmiotu.Ulica = "SomeStreet";
jpk.Podmiot1.AdresPodmiotu.NrDomu = 81;
jpk.Podmiot1.AdresPodmiotu.NrLokalu = 1;
jpk.Podmiot1.AdresPodmiotu.Miejscowosc = "Danzig";
jpk.Podmiot1.AdresPodmiotu.KodPocztowy = "10-101";
//Faktura
JpkFaktura jpkFaktura = new JpkFaktura();
jpkFaktura.KodWaluty = "PLN";
jpkFaktura.P_1 = "2021-05-04";
jpkFaktura.P_2A = "11 / 1111";
jpkFaktura.P_3A = "Some Company";
jpkFaktura.P_3B = "Some Address";
jpkFaktura.P_3C = "Some Name";
jpkFaktura.P_3D = "Some Other Address";
jpkFaktura.P_4B = "Phone1";
jpkFaktura.P_5B = "Phone2";
jpkFaktura.P_13_1 = 1.00m; //need to use 'm' for decimal number
jpkFaktura.P_14_1 = 1.25m; //need to use 'm' for decimal number
jpkFaktura.P_15 = 0m; //need to use 'm' for decimal number
jpkFaktura.P_16 = false;
jpkFaktura.P_17 = false;
jpkFaktura.P_18 = false;
jpkFaktura.P_18A = false;
jpkFaktura.P_19 = false;
jpkFaktura.P_20 = false;
jpkFaktura.P_21 = false;
jpkFaktura.P_22 = false;
jpkFaktura.P_23 = false;
jpkFaktura.P_106E_2 = false;
jpkFaktura.P_106E_3 = false;
jpkFaktura.RodzajFaktury = "InvoiceType";
//add
jpk.Faktura.Add(jpkFaktura);
//FakturaCtrl
JpkFakturaCtrl jpkFakturaCtrl = new JpkFakturaCtrl();
jpkFakturaCtrl.LiczbaFaktur = 1m; //need to use 'm' for decimal number
jpkFakturaCtrl.WartoscFaktur = 2.00m; //need to use 'm' for decimal number
//add
jpk.FakturaCtrl.Add(jpkFakturaCtrl);
//FakturaWiersz
JpkFakturaWiersz jpkFakturaWiersz = new JpkFakturaWiersz();
jpkFakturaWiersz.P_2B = "04/123";
jpkFakturaWiersz.P_7 = "Text";
jpkFakturaWiersz.P_8B = 1.000000m; //need to use 'm' for decimal number
jpkFakturaWiersz.P_9A = 7.00m; //need to use 'm' for decimal number
jpkFakturaWiersz.P_11 = 7.00m; //need to use 'm' for decimal number
jpkFakturaWiersz.P_12 = 11;
//add
jpk.FakturaWiersz.Add(jpkFakturaWiersz);
//FakturaWierszCtrl
JpkFakturaWierszCtrl jpkFakturaWierszCtrl = new JpkFakturaWierszCtrl();
jpkFakturaWierszCtrl.LiczbaWierszyFaktur = 11m; //need to use 'm' for decimal number
jpkFakturaWierszCtrl.WartoscWierszyFaktur = 11.2m; //need to use 'm' for decimal number
//add
jpk.FakturaWierszCtrl.Add(jpkFakturaWierszCtrl);
return jpk;
}
Usage:
Jpk jpk1 = CreateTestData();
For XML serialization, use the following:
public static void SerializeObjectToXMLFile(object obj, string xmlFilename)
{
try
{
if (string.IsNullOrEmpty(xmlFilename))
{
return;
}//if
using (System.IO.TextWriter xmlStream = new System.IO.StreamWriter(xmlFilename))
{
//specify namespaces
System.Xml.Serialization.XmlSerializerNamespaces ns = new System.Xml.Serialization.XmlSerializerNamespaces();
ns.Add(string.Empty, "http://jpk.mf.gov.pl/wzor/2019/09/27/09271/");
ns.Add("etd", "http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2018/08/24/eD/DefinicjeTypy/");
//create new instance
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
//write XML to file
serializer.Serialize(xmlStream, obj, ns);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
throw ex;
}
}
Usage:
Jpk jpk1 = CreateTestData();
SerializeObjectToXMLFile(jpk1, #"C:\Temp\Test.xml");
For deserialization, use the following code:
public static T DeserializeXMLFileToObject<T>(string xmlFilename)
{
T rObject = default(T);
try
{
if (string.IsNullOrEmpty(xmlFilename))
{
return default(T);
}
using (System.IO.StreamReader xmlStream = new System.IO.StreamReader(xmlFilename))
{
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
rObject = (T)serializer.Deserialize(xmlStream);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
throw ex;
}
return rObject;
}
Usage:
Jpk jpk1 = DeserializeXMLFileToObject<Jpk>(#"C:\Temp\Test.xml");

XML not being serialised correctly into object

I am trying to serialise a piece of XML that is being returned from a third party API. However when doing so i am only retrieving part of the object upon serialisation. And only some of the values seem to exist. I thought this could be a input type problem, however all the types seem to be correct. I think it may have something to do with how my model is constructed.After debugging the code i have narrowed it down to be a problem with the conversion of the xml into the object.
C# CODE:
//[Route("api/AvailabiliyCheck/GetAvailability/{CSSDistrictCode}/{GoldAddressKey}")]
public EADAvailabilityDetails GetAvailabilityEAD([FromUri] string CSSDistrictCode, [FromUri] string GoldAddressKey)
{
//Load the request xml template
XmlDocument doc = new XmlDocument();
string path = HttpContext.Current.Server.MapPath("~/XML/Availability/GetAvailabilityEAD.xml");
doc.Load(path);
//Assign incoming paramaters to xml template
XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable);
manager.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
manager.AddNamespace("stupid_xmlns", "http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService");
XmlNode CSSDistrictCodeNode = doc.SelectSingleNode("soap:Envelope/soap:Body/stupid_xmlns:GetAvailability/stupid_xmlns:request/stupid_xmlns:RequestDetails/stupid_xmlns:CSSDistrictCode", manager);
CSSDistrictCodeNode.InnerXml = CSSDistrictCode;
XmlNode GoldAddressKeyNode = doc.SelectSingleNode("soap:Envelope/soap:Body/stupid_xmlns:GetAvailability/stupid_xmlns:request/stupid_xmlns:RequestDetails/stupid_xmlns:GoldAddressKey", manager);
GoldAddressKeyNode.InnerXml = GoldAddressKey;
//Send Request To API
string _url = "https://b2b.api.talktalkgroup.com/api/v2/partners/AvailabilityCheckers/NPAC/v45";
string _action = "http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService/NetworkProductAvailabilityCheckerService/GetAvailability";
string xml = doc.InnerXml;
var soapResult = WebService.ApiRequest(_url, _action, xml);
XmlDocument xmlToFormat = new XmlDocument();
xmlToFormat.LoadXml(soapResult);
string Outerxml = xmlToFormat.FirstChild.FirstChild.FirstChild.FirstChild.ChildNodes[2].InnerXml;
//Remove all namespaces
var xmlToBeStripped = XElement.Parse(Outerxml);
string finalXml = XmlFormatter.stripNS(xmlToBeStripped).ToString();
EADAvailabilityDetails result;
// Deserialises xlm into an object
XmlSerializer serializer = new XmlSerializer(typeof(EADAvailabilityDetails));
using (TextReader reader = new StringReader(finalXml))
{
result = (EADAvailabilityDetails)serializer.Deserialize(reader);
}
return result;
}
XML being returned:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<GetAvailabilityResponse xmlns="http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService">
<GetAvailabilityResult xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Status xmlns="http://schemas.datacontract.org/2004/07/InHouse.SharedLibraries.ServiceBase.BaseTypes">
<Errors/>
<HasErrors>false</HasErrors>
</Status>
<CSSDistrictCode>lv</CSSDistrictCode>
<EADAvailability>
<AvailabilityDetails i:type="EADAvailabilityDetails">
<Status xmlns="http://schemas.datacontract.org/2004/07/InHouse.SharedLibraries.ServiceBase.BaseTypes">
<Errors/>
<HasErrors>false</HasErrors>
</Status>
<EADAvailability>
<EADAvailabilityResult>
<CollectorNodeExchangeCode>NDMAI</CollectorNodeExchangeCode>
<CollectorNodeExchangeName>Maidstone</CollectorNodeExchangeName>
<Distance>0</Distance>
<EADBandwidth xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a:string>100M</a:string>
</EADBandwidth>
<EADSubType>EAD-LA</EADSubType>
<FibreExchangeCode>NDACO</FibreExchangeCode>
<FibreExchangename>Archers Court</FibreExchangename>
<IndicativeECC>Within tariff</IndicativeECC>
<IndicativeOrderCategory>Category 2.1</IndicativeOrderCategory>
<LocalExchangeCode>NDACO</LocalExchangeCode>
<LocalExchangeName>Archers Court</LocalExchangeName>
<ORLeadTime>40</ORLeadTime>
<OrderCategoryExplanation>There is a T node within 1km (or 650m in London) with spare capacity and ducting is in place, however some additional cabling is required between the premises and the T node.</OrderCategoryExplanation>
<TTLeadTime>56</TTLeadTime>
<Zone>0</Zone>
</EADAvailabilityResult>
<EADAvailabilityResult>
<CollectorNodeExchangeCode>NDMAI</CollectorNodeExchangeCode>
<CollectorNodeExchangeName>Maidstone</CollectorNodeExchangeName>
<Distance>0</Distance>
<EADBandwidth xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a:string>LOW 1GB</a:string>
</EADBandwidth>
<EADSubType>EAD-LA</EADSubType>
<FibreExchangeCode>NDACO</FibreExchangeCode>
<FibreExchangename>Archers Court</FibreExchangename>
<IndicativeECC>Within tariff</IndicativeECC>
<IndicativeOrderCategory>Category 2.1</IndicativeOrderCategory>
<LocalExchangeCode>NDACO</LocalExchangeCode>
<LocalExchangeName>Archers Court</LocalExchangeName>
<ORLeadTime>40</ORLeadTime>
<OrderCategoryExplanation>There is a T node within 1km (or 650m in London) with spare capacity and ducting is in place, however some additional cabling is required between the premises and the T node.</OrderCategoryExplanation>
<TTLeadTime>56</TTLeadTime>
<Zone>0</Zone>
</EADAvailabilityResult>
<EADAvailabilityResult>
<CollectorNodeExchangeCode>NDCAN</CollectorNodeExchangeCode>
<CollectorNodeExchangeName>Canterbury</CollectorNodeExchangeName>
<Distance>20656</Distance>
<EADBandwidth xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a:string>HIGH 1GB</a:string>
</EADBandwidth>
<EADSubType>EAD-NonLA</EADSubType>
<FibreExchangeCode>NDCAN</FibreExchangeCode>
<FibreExchangename>Canterbury</FibreExchangename>
<IndicativeECC>Within tariff</IndicativeECC>
<IndicativeOrderCategory>Category 2.1</IndicativeOrderCategory>
<LocalExchangeCode>NDACO</LocalExchangeCode>
<LocalExchangeName>Archers Court</LocalExchangeName>
<ORLeadTime>40</ORLeadTime>
<OrderCategoryExplanation>There is a T node within 1km (or 650m in London) with spare capacity and ducting is in place, however some additional cabling is required between the premises and the T node.</OrderCategoryExplanation>
<TTLeadTime>56</TTLeadTime>
<Zone>B</Zone>
</EADAvailabilityResult>
</EADAvailability>
<LeadTime>10</LeadTime>
</AvailabilityDetails>
</EADAvailability>
<GoldAddressKey>A00009292752</GoldAddressKey>
<Postcode/>
</GetAvailabilityResult>
</GetAvailabilityResponse>
</s:Body>
</s:Envelope>
Model:
[Serializable, XmlRoot("AvailabilityDetails")]
public class EADAvailabilityDetails
{
[XmlElement("EADAvailability")]
public EADAvailability EADAvailability { get; set; }
}
public class EADAvailability
{
[XmlElement("EADAvailabilityResult")]
public List<EADAvailabilityResult> EADAvailabilityResult { get; set; }
}
public class EADAvailabilityResult
{
[XmlElement("CollectorNodeExchangeCode")]
public string CollectorNodeExchangeCode { get; set; }
[XmlElement("CollectorNodeExchangeName")]
public string CollectorNodeExchangeName { get; set; }
[XmlElement("Distance")]
public int Distance { get; set; }
[XmlElement("EADBandwidth")]
public string EADBandwidth { get; set; }
[XmlElement("EADSubType")]
public string EADSubType { get; set; }
[XmlElement("FibreExchangeCode")]
public string FibreExchangeCode { get; set; }
[XmlElement("FibreExchangename")]
public string FibreExchangename { get; set; }
[XmlElement("IndicativeECC")]
public string IndicativeECC { get; set; }
[XmlElement("IndicativeOrderCategory")]
public string IndicativeOrderCategory { get; set; }
[XmlElement("LocalExchangeCode")]
public string LocalExchangeCode { get; set; }
[XmlElement("LocalExchangeName")]
public string LocalExchangeName { get; set; }
[XmlElement("ORLeadTime")]
public int ORLeadTime { get; set; }
[XmlElement("OrderCategoryExplanation")]
public string OrderCategoryExplanation { get; set; }
[XmlElement("TTLeadTime")]
public int TTLeadTime { get; set; }
[XmlElement("Zone")]
public int Zone { get; set; }
}
XML after serialisation:
{
"<EADAvailability>k__BackingField": {
"EADAvailabilityResult": [
{
"CollectorNodeExchangeCode": "NDMAI",
"CollectorNodeExchangeName": "Maidstone",
"Distance": 0,
"EADBandwidth": "100M",
"EADSubType": null,
"FibreExchangeCode": null,
"FibreExchangename": null,
"IndicativeECC": null,
"IndicativeOrderCategory": null,
"LocalExchangeCode": null,
"LocalExchangeName": null,
"ORLeadTime": 0,
"OrderCategoryExplanation": null,
"TTLeadTime": 0,
"Zone": 0
}
]
}
}
The code below works :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication139
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
XmlSerializer serializer = new XmlSerializer(typeof(Envelope));
Envelope envelope = (Envelope)serializer.Deserialize(reader);
}
}
[XmlRoot(Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class Envelope
{
[XmlElement (Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public Body Body { get; set; }
}
public class Body
{
[XmlElement(Namespace = "http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService")]
public GetAvailabilityResponse GetAvailabilityResponse { get; set; }
}
public class GetAvailabilityResponse
{
[XmlElement(Namespace = "http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService")]
public GetAvailabilityResult GetAvailabilityResult { get; set; }
}
public class GetAvailabilityResult
{
[XmlArray("EADAvailability", Namespace = "http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService")]
[XmlArrayItem("AvailabilityDetails", Namespace = "http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService")]
public AvailabilityDetails[] AvailabilityDetails { get; set; }
}
[XmlInclude(typeof(EADAvailabilityDetails))]
[Serializable, XmlRoot("AvailabilityDetails", Namespace = "http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService")]
public class AvailabilityDetails
{
}
[Serializable, XmlRoot("EADAvailabilityDetails", Namespace = "http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService")]
public class EADAvailabilityDetails : AvailabilityDetails
{
[XmlArray("EADAvailability", Namespace = "http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService")]
[XmlArrayItem("EADAvailabilityResult", Namespace = "http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService")]
public EADAvailabilityResult[] EADAvailabilityResult { get; set; }
}
public class EADAvailabilityResult
{
public string CollectorNodeExchangeCode { get; set; }
public string CollectorNodeExchangeName { get; set; }
public int Distance { get; set; }
public EADBandwidth EADBandwidth { get; set; }
public string EADSubType { get; set; }
public string FibreExchangeCode { get; set; }
public string FibreExchangename { get; set; }
public string IndicativeECC { get; set; }
public string IndicativeOrderCategory { get; set; }
public string LocalExchangeCode { get; set; }
public string LocalExchangeName { get; set; }
public int ORLeadTime { get; set; }
public string OrderCategoryExplanation { get; set; }
public int TTLeadTime { get; set; }
public string Zone { get; set; }
}
public class EADBandwidth
{
[XmlElement(ElementName = "string", Type = typeof(string), Namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays")]
public string String { get; set; }
}
}

Deserialize XML values to objects

I'm trying to use XDocument to read in XML and deserialize it to objects.
I want to take the following XML:
<r25:spaces xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xl="http://www.w3.org/1999/xlink" xmlns:r25="http://www.collegenet.com/r25" pubdate="2019-07-15T14:51:16-07:00" engine="accl">
<r25:space crc="00000022" status="est" xl:href="space.xml?space_id=200">
<r25:space_id>200</r25:space_id>
<r25:space_name>LRN 0001</r25:space_name>
<r25:formal_name>Learning Commons -Test Scheduling Room</r25:formal_name>
<r25:partition_id xl:href="rmpart.xml?partition_id=2">2</r25:partition_id>
<r25:last_mod_dt>2019-07-11T08:01:00-07:00</r25:last_mod_dt>
</r25:space>
</r25:spaces>
and deserialize it to a List of spaces (where Space has the following definition):
public class Space
{
public long space_id { get; set; }
public string space_name { get; set; }
public string formal_name { get; set; }
public long partition_id { get ; set; }
public DateTime last_mod_dt { get; set; }
}
I've only gotten so far as to get the XElement. It dies on the serializer
var doc = XDocument.Parse(result.Content);
XNamespace ns = "http://www.collegenet.com/r25";
XElement el = doc.Element(ns + "spaces");
foreach (var space in el.Elements())
{
var serializer = new XmlSerializer(typeof(Space));
var s = (Space)serializer.Deserialize(space.CreateReader());
}
You can simply use LINQ to XML here. e.g.
using System;
using System.Linq;
using System.Xml.Linq;
namespace ConsoleApp22
{
public class Space
{
public long space_id { get; set; }
public string space_name { get; set; }
public string formal_name { get; set; }
public long partition_id { get; set; }
public DateTime last_mod { get; set; }
}
class Program
{
static void Main(string[] args)
{
var xml = #"
<r25:spaces xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xl=""http://www.w3.org/1999/xlink"" xmlns:r25=""http://www.collegenet.com/r25"" pubdate=""2019-07-15T14:51:16-07:00"" engine=""accl"">
<r25:space crc=""00000022"" status=""est"" xl:href=""space.xml?space_id=200"">
<r25:space_id>200</r25:space_id>
<r25:space_name>LRN 0001</r25:space_name>
<r25:formal_name>Learning Commons -Test Scheduling Room</r25:formal_name>
<r25:partition_id xl:href=""rmpart.xml?partition_id=2"">2</r25:partition_id>
<r25:last_mod_dt>2019-07-11T08:01:00-07:00</r25:last_mod_dt>
</r25:space>
</r25:spaces>
";
var doc = XDocument.Parse(xml);
XNamespace ns = "http://www.collegenet.com/r25";
var q = from e in doc.Element(ns + "spaces").Elements()
select new Space
{
space_id = (int)e.Element(ns + "space_id"),
space_name = (string)e.Element(ns + "space_name"),
formal_name = (string)e.Element(ns + "formal_name"),
partition_id = (long)e.Element(ns + "partition_id"),
last_mod = (DateTime)e.Element(ns + "last_mod_dt")
};
var space = q.First();
}
}
}
You can add the XmlRoot to your class to declare the namespace for that element:
[XmlRoot("space", Namespace = "http://www.collegenet.com/r25")]
public class Space
{
public long space_id { get; set; }
public string space_name { get; set; }
public string formal_name { get; set; }
public long partition_id { get; set; }
public DateTime last_mod { get; set; }
}
The deserializer will now correctly read the XML as an object.
Use the the XSD tool to generate the class and then use XmlSerializer to populate the class. Like this.
MyClass myClass;
using (var stream = new FileStream("myClass.xml", FileMode.Open))
{
var serializer = new XmlSerializer(typeof(MyClass));
myClass = serializer.Deserialize(stream);
}
I found a website that will take XML and create the proper deserialization classes. Xml2CSharp, which created the following classes that allowed the deserialization to work:
[XmlRoot(ElementName="partition_id", Namespace="http://www.collegenet.com/r25")]
public class Partition_id {
[XmlAttribute(AttributeName="href", Namespace="http://www.w3.org/1999/xlink")]
public string Href { get; set; }
[XmlText]
public string Text { get; set; }
}
[XmlRoot(ElementName="space", Namespace="http://www.collegenet.com/r25")]
public class Space {
[XmlElement(ElementName="space_id", Namespace="http://www.collegenet.com/r25")]
public string Space_id { get; set; }
[XmlElement(ElementName="space_name", Namespace="http://www.collegenet.com/r25")]
public string Space_name { get; set; }
[XmlElement(ElementName="formal_name", Namespace="http://www.collegenet.com/r25")]
public string Formal_name { get; set; }
[XmlElement(ElementName="partition_id", Namespace="http://www.collegenet.com/r25")]
public Partition_id Partition_id { get; set; }
[XmlElement(ElementName="last_mod_dt", Namespace="http://www.collegenet.com/r25")]
public string Last_mod_dt { get; set; }
[XmlAttribute(AttributeName="crc")]
public string Crc { get; set; }
[XmlAttribute(AttributeName="status")]
public string Status { get; set; }
[XmlAttribute(AttributeName="href", Namespace="http://www.w3.org/1999/xlink")]
public string Href { get; set; }
}
[XmlRoot(ElementName="spaces", Namespace="http://www.collegenet.com/r25")]
public class Spaces {
[XmlElement(ElementName="space", Namespace="http://www.collegenet.com/r25")]
public Space Space { get; set; }
[XmlAttribute(AttributeName="xsi", Namespace="http://www.w3.org/2000/xmlns/")]
public string Xsi { get; set; }
[XmlAttribute(AttributeName="xl", Namespace="http://www.w3.org/2000/xmlns/")]
public string Xl { get; set; }
[XmlAttribute(AttributeName="r25", Namespace="http://www.w3.org/2000/xmlns/")]
public string R25 { get; set; }
[XmlAttribute(AttributeName="pubdate")]
public string Pubdate { get; set; }
[XmlAttribute(AttributeName="engine")]
public string Engine { get; set; }
}

Trying to Export data in mongodb but got this Error ?Expected a nested document representing

Expected a nested document representing the serialized form of a Rootobject value, but found a value of type Array instead?
C# Code:
My guess is that I should write a custom serializer for that class but I couldn't find any useful example in the MONGODB .NET DRIVER Manual.
I'm working with C# MongoDB driver
string inputFileName = #"1546346582.07002.json"; // initialize to the input file
IMongoCollection<Rootobject> coll = database.GetCollection<Rootobject>("BB");
using (var streamReader = new StreamReader(inputFileName))
{
string line;
while ((line = streamReader.ReadLine()) != null)
{
using (var jsonReader = new MongoDB.Bson.IO.JsonReader(line))
{
var context = BsonDeserializationContext.CreateRoot(jsonReader);
var document = coll.DocumentSerializer.Deserialize(context);
coll.InsertOne(document);
}
}
}
public class Rootobject
{
[BsonElement ("Property1")]
public Class1[] Property1 { get; set; }
}
public class Class1
{
[BsonId]
public ObjectId _id { get; set; }
[BsonElement ("ID")]
public string account { get; set; }
[BsonElement ("Account")]
public string accuser { get; set; }
[BsonElement ("Accuser")]
public string bookedby { get; set; }
[BsonElement ("BookedBy")]
public bool changed { get; set; }
[BsonElement ("Changed")]
}
public class Fromtovia
{
public string info { get; set; }
[BsonElement ("Info")]
public string address { get; set; }
[BsonElement("Address")]
public float lat { get; set; }
[BsonElement("Latitude")]
public float lon { get; set; }
[BsonElement("longitude")]
public string postcode { get; set; }
}
But I couldn't find anything Useful.

Deserialize an xml not extract the object

I want to deserialize an XML string to an object. the execution don't return an error or an exception. I search in net but don't find any solution that I can apply to my issue.
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "Get_mouvements_usersResult";
xRoot.Namespace = "urn:DME_Webservices";
xRoot.IsNullable = false;
trueObject="<ns1:Get_mouvements_usersResult xmlns:ns1=\"urn:DME_Webservices\"><Obj_info_retour><flag_erreur>false</flag_erreur><libelle_erreur/><libelle_detail_erreur/></Obj_info_retour><tab_Cuser_mouvements><obj_cuser><IPP>02084</IPP><Id_user>4503843842</Id_user><civilite>Mme</civilite><nom_usuel>BOTTU</nom_usuel><nom_naissance>LOACU</nom_naissance><prenom>Alida</prenom><date_naissance>19340707</date_naissance><numro_sejour>31202084001</numro_sejour><date_deb_sejour>20150420113700</date_deb_sejour><code_lit>504</code_lit><code_etablissement>000312</code_etablissement></obj_cuser><tab_obj_Cmouvement>Id_mouvement>4505631384</Id_mouvement><date_mouvement>20150420113700</date_mouvement><code_mouvement>E</code_mouvement><Libelle_mouvement>Entre tablissement</Libelle_mouvement><code_ufh>ETG1</code_ufh><libelle_ufh>Etage 1-Chteau de Fermaincourt</libelle_ufh><code_ufm>SSR_HC_CONVA</code_ufm><libelle_ufm>Convalescence</libelle_ufm><Date_fin_mouvement>20150422152600</Date_fin_mouvement><code_lit>402</code_lit><comm_mouvement/>/tab_obj_Cmouvement><tab_obj_Cmouvement><Id_mouvement>4533166359</Id_mouvement><date_mouvement>20150422152600</date_mouvement><code_mouvement>M</code_mouvement><Libelle_mouvement>Mutation</Libelle_mouvement>code_ufh>ETG3</code_ufh><libelle_ufh>Etage 3 - La Chapelle Royale</libelle_ufh><code_ufm>SSR_HC_CONVA</code_ufm><libelle_ufm>Convalescence</libelle_ufm><Date_fin_mouvement>20150730142100</Date_fin_mouvement>code_lit>605D</code_lit><comm_mouvement/></tab_obj_Cmouvement><tab_obj_Cmouvement><Id_mouvement>5125097053</Id_mouvement><date_mouvement>20150730142100</date_mouvement><code_mouvement>M</code_mouvement><Libelle_mouvement>Mutation</Libelle_mouvement><code_ufh>ETG2</code_ufh><libelle_ufh>Etage 2 - Domaine de Comteville</libelle_ufh><code_ufm>SSR_HC_SDSG</code_ufm><libelle_ufm>Griatrie</libelle_ufm><Date_fin_mouvement/><code_lit>504</code_lit><comm_mouvement/></tab_obj_Cmouvement></tab_Cuser_mouvements></ns1:Get_mouvements_usersResult>";
MemoryStream stream = new MemoryStream(UTF8Encoding.UTF8.GetBytes(trueObject));
XmlSerializer serializer = new XmlSerializer(typeof(XmlUsers), xRoot);
listXmlUserMove = (XmlUsers)serializer.Deserialize(stream);
I have these classes:
[Serializable, XmlRoot("ns1:Get_mouvements_usersResult"), XmlType("ns1:Get_mouvements_usersResult")]
public class XmlUsers
{
[XmlElement("tab_Cuser_mouvements")]
public List<XmlUserMove> UserList { get; set; }
[XmlElement("Obj_info_retour")]
public SoapResult soapResult { get; set; }
}
[XmlType("Obj_info_retour")]
public class SoapResult
{
[XmlElement("flag_erreur")]
public string ErrorFlag { get; set; }
[XmlElement("libelle_erreur")]
public string ErrorName { get; set; }
[XmlElement("libelle_detail_erreur")]
public string ErrorDetails { get; set; }
}
[XmlType("tab_Cuser_mouvements")]
public class XmlUserMove
{
[XmlElement("obj_cuser")]
public XmlUser user { get; set; }
[XmlElement("tab_obj_Cmouvement")]
public List<XmlMove> MoveList { get; set; }
}
public class XmlUser
{
[XmlElementAttribute("IPP")]
public string IPP { get; set; }
[XmlElementAttribute("Id_patient")]
public string IdUser { get; set; }
[XmlElementAttribute("civilite")]
public string Title { get; set; }
[XmlElementAttribute("nom_usuel")]
public string UsedLastName { get; set; }
[XmlElementAttribute("nom_naissance")]
public string BirthLastName { get; set; }
[XmlElementAttribute("prenom")]
public string FirstName { get; set; }
[XmlElementAttribute("date_naissance")]
public string Birthday { get; set; }
[XmlElementAttribute("numero_sejour")]
public string RoomNumber { get; set; }
[XmlElementAttribute("date_deb_sejour")]
public string EntredDate { get; set; }
[XmlElementAttribute("code_lit")]
public string BedCode { get; set; }
[XmlElementAttribute("code_etablissement")]
public string DivisionCode { get; set; }
}
public class XmlMove
{
[XmlElement("Id_mouvement")]
public string MoveId { get; set; }
[XmlElement("date_mouvement")]
public string MoveDate { get; set; }
[XmlElement("code_mouvement")]
public string MoveCode { get; set; }
[XmlElement("Libelle_mouvement")]
public string MoveName { get; set; }
[XmlElement("code_ufh")]
public string ufhCode { get; set; }
[XmlElement("libelle_ufh")]
public string UfhName { get; set; }
[XmlElement("code_ufm")]
public string UfmCode { get; set; }
[XmlElement("libelle_ufm")]
public string UfmName { get; set; }
[XmlElement("Date_fin_mouvement")]
public string MoveEndDate { get; set; }
[XmlElement("code_lit")]
public string BedCode { get; set; }
[XmlElement("comm_mouvement")]
public string MoveComm { get; set; }
}
The listXmlUserMove object don't contain anything but the xml contain many things.
Any one can help me please?
There are a few < characters missing from your trueObject, and you didn't include the XmlUser class, but since you reported an empty object and not an exception, I'm assuming what you have is really ok, and that was just a copy/paste error.
You don't need to declare the xRoot object separately if you get the attributes on XmlUsers set up correctly. ns1 is meaningless without context. You should use the Namespace property to give the info to those attributes correctly.
[Serializable, XmlRoot("Get_mouvements_usersResult", Namespace = "urn:DME_Webservices"), XmlType("Get_mouvements_usersResult", Namespace = "urn:DME_Webservices")]
public class XmlUsers
Your elements aren't coming through because of a namespace issue. XmlUsers's Namespace is assumed to apply to the elements inside of it. In your actual XML, though, they are in a different namespace. Since they have no xmlns defined, they're in the default namespace, an empty string. The element's namespaces should be set explicitly:
[Serializable, XmlRoot("Get_mouvements_usersResult", Namespace = "urn:DME_Webservices"), XmlType("Get_mouvements_usersResult", Namespace = "urn:DME_Webservices")]
public class XmlUsers
{
[XmlElement("tab_Cuser_mouvements", Namespace = "")]
public List<XmlUserMove> UserList { get; set; }
[XmlElement("Obj_info_retour", Namespace = "")]
public SoapResult soapResult { get; set; }
}
If you had intended everything to be inside ns1, then you'll need to rework your XML files and classes to match that.
So now the code to deserialize looks like this (note, this includes my fixed trueObject string)
var trueObject="<ns1:Get_mouvements_usersResult xmlns:ns1=\"urn:DME_Webservices\"><Obj_info_retour><flag_erreur>false</flag_erreur><libelle_erreur/><libelle_detail_erreur/></Obj_info_retour><tab_Cuser_mouvements><obj_cuser><IPP>02084</IPP><Id_user>4503843842</Id_user><civilite>Mme</civilite><nom_usuel>BOTTU</nom_usuel><nom_naissance>LOACU</nom_naissance><prenom>Alida</prenom><date_naissance>19340707</date_naissance><numro_sejour>31202084001</numro_sejour><date_deb_sejour>20150420113700</date_deb_sejour><code_lit>504</code_lit><code_etablissement>000312</code_etablissement></obj_cuser><tab_obj_Cmouvement><Id_mouvement>4505631384</Id_mouvement><date_mouvement>20150420113700</date_mouvement><code_mouvement>E</code_mouvement><Libelle_mouvement>Entre tablissement</Libelle_mouvement><code_ufh>ETG1</code_ufh><libelle_ufh>Etage 1-Chteau de Fermaincourt</libelle_ufh><code_ufm>SSR_HC_CONVA</code_ufm><libelle_ufm>Convalescence</libelle_ufm><Date_fin_mouvement>20150422152600</Date_fin_mouvement><code_lit>402</code_lit><comm_mouvement/></tab_obj_Cmouvement><tab_obj_Cmouvement><Id_mouvement>4533166359</Id_mouvement><date_mouvement>20150422152600</date_mouvement><code_mouvement>M</code_mouvement><Libelle_mouvement>Mutation</Libelle_mouvement><code_ufh>ETG3</code_ufh><libelle_ufh>Etage 3 - La Chapelle Royale</libelle_ufh><code_ufm>SSR_HC_CONVA</code_ufm><libelle_ufm>Convalescence</libelle_ufm><Date_fin_mouvement>20150730142100</Date_fin_mouvement><code_lit>605D</code_lit><comm_mouvement/></tab_obj_Cmouvement><tab_obj_Cmouvement><Id_mouvement>5125097053</Id_mouvement><date_mouvement>20150730142100</date_mouvement><code_mouvement>M</code_mouvement><Libelle_mouvement>Mutation</Libelle_mouvement><code_ufh>ETG2</code_ufh><libelle_ufh>Etage 2 - Domaine de Comteville</libelle_ufh><code_ufm>SSR_HC_SDSG</code_ufm><libelle_ufm>Griatrie</libelle_ufm><Date_fin_mouvement/><code_lit>504</code_lit><comm_mouvement/></tab_obj_Cmouvement></tab_Cuser_mouvements></ns1:Get_mouvements_usersResult>";
MemoryStream stream = new MemoryStream(UTF8Encoding.UTF8.GetBytes(trueObject));
XmlSerializer serializer = new XmlSerializer(typeof(XmlUsers));
var listXmlUserMove = (XmlUsers)serializer.Deserialize(stream);
But the object is actually populated at the end!
I do what Tim S. tell me but I don't remove the xRoot :
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "Get_mouvements_usersResult";
xRoot.Namespace = "urn:DME_Webservices";
xRoot.IsNullable = false;
.
XmlSerializer serializer = new XmlSerializer(typeof(XmlUsers), xRoot);
Now the solution work fine.
Thank you for your help :)

Categories