Create a dynamic XML file by taking a sample XML - c#

I have to create a dynamic XML taking an XML as an example.
E.g.:
<root>
<cde>
<id1>11</id1>
<id2>aa3</id2>
<listProducts>
<Products>
<id>123123</ndg>
<Name>AAFFF</Name>
<listProductsService>
<ProductsService>
<id>AA22</id>
<numRapp>324554</numRapp>
</ProductsService>
</listProductsService>
<listProcess>
<idProcessItem>FDD223</idProcessItem>
</listProcess>
</Products>
</listProducts>
<ddd>DSSVDDSS</ddd>
<dateVar>2022/02/22 12:15:00</dateVar>
</cde>
<fgh>
<id1>AB223</id1>
<idDoc>AACC4454</idDoc>
<idAAA>CCCVV223</idAAA>
<progrVers>1</progrVers>
<listCF>
<DescrCF>
<id>123456</id>
<descr>VVVV</descr>
<cgggg>AAAAA</cgggggg>
</DescrCF>
</listCF>
<bbbffd>VVVVV</bbbffd>
<hhhggg>DDDDDDDD</hhhggg>
</fgh>
<cde>
<id1>55</id1>
<id2>bbff3</id2>
<listProducts>
<Products>
<id>123123</ndg>
<Name>AAFFF</Name>
<listProductsService>
<ProductsService>
<id>AA22</id>
<numRapp>324554</numRapp>
</ProductsService>
</listProductsService>
<listProcess>
<idProcessItem>FDD223</idProcessItem>
</listProcess>
</Products>
</listProducts>
<ddd>DSSVDDSS</ddd>
<dateVar>2022/02/22 12:15:00</dateVar>
</cde>
<fgh>
<id>FFFVVGG332</id>
<idDoc>FFC33</idDoc>
<idAAA>CCCVV223</idAAA>
<progrVers>1</progrVers>
<listCF>
<DescrCF>
<id>123456</id>
<descr>VVVV</descr>
<cgggg>AAAAA</cgggggg>
</DescrCF>
</listCF>
<bbbffd>VVVVV</bbbffd>
<hhhggg>DDDDDDDD</hhhggg>
</fgh>
</root>
I have to cycle <cde> and <fgh> for all the data coming to me. How can I do to create this XML dynamically by cycling them? root must be only one.
Tast thing: the id1 of <cde> and <fgh> must match in the xml file.
I tried to create a dto model and then loop the data but nothing. I tried to create a dummy JSON but nothing. Do you have any suggestions?
I tried creating a class with all the data:
public class root
{
public cde cde { get; set; }
public fgh fgh { get; set; }
}
public class cde
{
public string id1 { get; set; }
public string id2 { get; set; }
public listProducts { get; set; }
}
....
to cycle the data:
var root = new List<Root>();
for(int i = 0; i < data.Count(); i++)
{
root.Add(root = new root
{
cde = new cde {
id1 = 11,
id2 = 222,
listProducts = new listProducts {
listProducts = new listProducts
{
....
}
}
}
}
}
as a final result I get a list.
To create XML I relied on XMLSerialize:
var settings = new XmlWriterSettings
{
Indent = true,
OmitXmlDeclaration = true,
Async = false
}
var ns = new XmlSerializerNamespaces(new[] {XmlQualifiedName.Empty});
Xmlserializer x = new Xmlserializer(root.GetType());
using(var writer = XmlWriter.Create(#"c:\test.xml", settings)
{
x.Serialize(writer, root, ns);
}
but my xml file looks like this:
<ArrayOfRoots>
<root>
<cde>
<id1>11</id1>
<id2>aa3</id2>
<listProducts>
<Products>
<id>123123</ndg>
<Name>AAFFF</Name>
<listProductsService>
<ProductsService>
<id>AA22</id>
<numRapp>324554</numRapp>
</ProductsService>
</listProductsService>
<listProcess>
<idProcessItem>FDD223</idProcessItem>
</listProcess>
</Products>
</listProducts>
<ddd>DSSVDDSS</ddd>
<dateVar>2022/02/22 12:15:00</dateVar>
</cde>
<fgh>
<id1>AB223</id1>
<idDoc>AACC4454</idDoc>
<idAAA>CCCVV223</idAAA>
<progrVers>1</progrVers>
<listCF>
<DescrCF>
<id>123456</id>
<descr>VVVV</descr>
<cgggg>AAAAA</cgggggg>
</DescrCF>
</listCF>
<bbbffd>VVVVV</bbbffd>
<hhhggg>DDDDDDDD</hhhggg>
</fgh>
<cde>
<id1>55</id1>
<id2>bbff3</id2>
<listProducts>
<Products>
<id>123123</ndg>
<Name>AAFFF</Name>
<listProductsService>
<ProductsService>
<id>AA22</id>
<numRapp>324554</numRapp>
</ProductsService>
</listProductsService>
<listProcess>
<idProcessItem>FDD223</idProcessItem>
</listProcess>
</Products>
</listProducts>
<ddd>DSSVDDSS</ddd>
<dateVar>2022/02/22 12:15:00</dateVar>
</cde>
<fgh>
<id>FFFVVGG332</id>
<idDoc>FFC33</idDoc>
<idAAA>CCCVV223</idAAA>
<progrVers>1</progrVers>
<listCF>
<DescrCF>
<id>123456</id>
<descr>VVVV</descr>
<cgggg>AAAAA</cgggggg>
</DescrCF>
</listCF>
<bbbffd>VVVVV</bbbffd>
<hhhggg>DDDDDDDD</hhhggg>
</fgh>
</root>
<root>
<cde>
<id1>11</id1>
<id2>aa3</id2>
<listProducts>
<Products>
<id>123123</ndg>
<Name>AAFFF</Name>
<listProductsService>
<ProductsService>
<id>AA22</id>
<numRapp>324554</numRapp>
</ProductsService>
</listProductsService>
<listProcess>
<idProcessItem>FDD223</idProcessItem>
</listProcess>
</Products>
</listProducts>
<ddd>DSSVDDSS</ddd>
<dateVar>2022/02/22 12:15:00</dateVar>
</cde>
<fgh>
<id1>AB223</id1>
<idDoc>AACC4454</idDoc>
<idAAA>CCCVV223</idAAA>
<progrVers>1</progrVers>
<listCF>
<DescrCF>
<id>123456</id>
<descr>VVVV</descr>
<cgggg>AAAAA</cgggggg>
</DescrCF>
</listCF>
<bbbffd>VVVVV</bbbffd>
<hhhggg>DDDDDDDD</hhhggg>
</fgh>
<cde>
<id1>55</id1>
<id2>bbff3</id2>
<listProducts>
<Products>
<id>123123</ndg>
<Name>AAFFF</Name>
<listProductsService>
<ProductsService>
<id>AA22</id>
<numRapp>324554</numRapp>
</ProductsService>
</listProductsService>
<listProcess>
<idProcessItem>FDD223</idProcessItem>
</listProcess>
</Products>
</listProducts>
<ddd>DSSVDDSS</ddd>
<dateVar>2022/02/22 12:15:00</dateVar>
</cde>
<fgh>
<id>FFFVVGG332</id>
<idDoc>FFC33</idDoc>
<idAAA>CCCVV223</idAAA>
<progrVers>1</progrVers>
<listCF>
<DescrCF>
<id>123456</id>
<descr>VVVV</descr>
<cgggg>AAAAA</cgggggg>
</DescrCF>
</listCF>
<bbbffd>VVVVV</bbbffd>
<hhhggg>DDDDDDDD</hhhggg>
</fgh>
</root>
</arrayofroots>
multiply all the root but I need only one root and several and

Your xml is NOT dynamic, it has a known format. When an XML file has a schema it is best to create c# classes using xsd.exe and use xml serialization. But this method is slow and usually leads to classes that have lots of layers and makes it harder to process the data due to number of layers of depth.
My approach is to attempt to flatten the data and use XML Linq (XDocument) to parse the data. Below are the classes I would use with your Xml. It appears that you xml tags that contain "list" are not really lists but a singleton from sample provided, but may really be lists.
public class Roots
{
public List<Root> roots { get; set; }
}
public class Root
{
public List<CDE> cde { get; set; }
public List<FGH> fgh { get; set; }
}
public class CDE
{
public int id1 { get; set; }
public string id2 { get; set; }
public int productID { get; set; }
public string productName { get; set; }
public string serviceID { get; set; }
public string numRapp { get; set; }
public string idProcessItem { get; set; }
}
public class FGH
{
public string id1 { get; set; }
public string idDoc { get; set; }
public string idAAA { get; set; }
public int progrVers { get; set; }
public int productId { get; set; }
public string productName { get; set; }
public string productService { get; set; }
public string serviceId { get; set; }
public string numRapp { get; set; }
public string idProcessItem { get; set; }
}

Related

Get XMLElement at any depth during deserialization

I am new to c# and XML deserialization, pardon me for any wrong words/mising any information.
I am deserializing a Nunit3 test result XML with root element as test-run and child elements are test-suite and then test-case.
test-case is repeated multiple times depending on number of test cases executed and also the element which I am interested in.
The C# class for the Nunit XML is like the following.
[XmlRoot(ElementName = "test-run")]
public class Testrun
{
[XmlElement(ElementName = "command-line")]
public string Commandline { get; set; }
[XmlElement(ElementName = "test-suite")]
public Testsuite Testsuite { get; set; }
}
[XmlRoot(ElementName = "test-suite")]
public class Testsuite
{
[XmlElement(ElementName = "test-case")]
public Testcase Testcase { get; set; }
}
But sometimes nested test-suite element occurs in Nunit XML as following.
<test-suite type="TestSuite" id="0-1005" name="TopGearFramework" fullname="TopGearFramework" runstate="Runnable" testcasecount="2" result="Failed" site="Child" start-time="2019-02-21 04:17:28Z" end-time="2019-02-21 04:19:16Z" duration="108.354384" total="2" passed="1" failed="1" warnings="0" inconclusive="0" skipped="0" asserts="14">
<test-suite type="TestSuite" id="0-1006" name="CFTestCases" fullname="TopGearFramework.CFTestCases" runstate="Runnable" testcasecount="2" result="Failed" site="Child" start-time="2019-02-21 04:17:28Z" end-time="2019-02-21 04:19:16Z" duration="108.353019" total="2" passed="1" failed="1" warnings="0" inconclusive="0" skipped="0" asserts="14">
<test-suite type="TestSuite" id="0-1007" name="PoCTestCases" fullname="TopGearFramework.CFTestCases.PoCTestCases" runstate="Runnable" testcasecount="2" result="Failed" site="Child" start-time="2019-02-21 04:17:28Z" end-time="2019-02-21 04:19:16Z" duration="108.352989" total="2" passed="1" failed="1" warnings="0" inconclusive="0" skipped="0" asserts="14">
<test-suite type="TestSuite" id="0-1008" name="FeatureFiles" fullname="TopGearFramework.CFTestCases.PoCTestCases.FeatureFiles" runstate="Runnable" testcasecount="2" result="Failed" site="Child" start-time="2019-02-21 04:17:28Z" end-time="2019-02-21 04:19:16Z" duration="108.352968" total="2" passed="1" failed="1" warnings="0" inconclusive="0" skipped="0" asserts="14">
<test-suite type="TestFixture" id="0-1002" name="IndividualDealerPartyCreationFeature" fullname="TopGearFramework.CFTestCases.PoCTestCases.FeatureFiles.IndividualDealerPartyCreationFeature" classname="TopGearFramework.CFTestCases.PoCTestCases.FeatureFiles.IndividualDealerPartyCreationFeature" runstate="Runnable" testcasecount="1" result="Passed" start-time="2019-02-21 04:17:28Z" end-time="2019-02-21 04:19:07Z" duration="99.414157" total="1" passed="1" failed="0" warnings="0" inconclusive="0" skipped="0" asserts="10">
<test-case id="0-1003" name="XF_PAM_004_CheckNewDealerPartyCreationForIndividual" fullname="TopGearFramework.CFTestCases.PoCTestCases.FeatureFiles.IndividualDealerPartyCreationFeature.XF_PAM_004_CheckNewDealerPartyCreationForIndividual" methodname="XF_PAM_004_CheckNewDealerPartyCreationForIndividual" classname="TopGearFramework.CFTestCases.PoCTestCases.FeatureFiles.IndividualDealerPartyCreationFeature" runstate="Runnable" seed="293675085" result="Passed" start-time="2019-02-21 04:17:29Z" end-time="2019-02-21 04:19:07Z" duration="98.585096" asserts="10">
Note that the test-suite is repeated 5 times before test-case occurs. With this during deserialization, I am getting null to test-case object.
How to handle the dynamic nesting or repetition of test-suite element to get the test-case?
Thanks in advance.
Edit 1# Full XML copied for reference.
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<test-run id="2" testcasecount="2" result="Failed" total="2" passed="1" failed="1" inconclusive="0" skipped="0" asserts="14" engine-version="3.9.0.0" clr-version="4.0.30319.42000" start-time="2019-02-21 04:17:25Z" end-time="2019-02-21 04:19:16Z" duration="111.183778">
<command-line><![CDATA["C:\Program Files (x86)\NUnit.org\nunit-console\nunit3-console.exe" TopGearFramework\bin\Debug\TopGearFramework.dll --result=TestResult.xml --labels=All --out=TestResult.txt]]></command-line>
<test-suite type="Assembly" id="0-1004" name="TopGearFramework.dll" fullname="TopGearFramework.dll" runstate="Runnable" testcasecount="2" result="Failed" site="Child" start-time="2019-02-21 04:17:28Z" end-time="2019-02-21 04:19:16Z" duration="108.409138" total="2" passed="1" failed="1" warnings="0" inconclusive="0" skipped="0" asserts="14">
<environment framework-version="3.11.0.0" clr-version="4.0.30319.42000" os-version="Microsoft Windows NT 10.0.16299.0" platform="Win32NT" cwd="C:\Users\qxm5789\.jenkins\workspace\TopGearTestRunner_master" machine-name="VMUC0034748" user="qxm5789" user-domain="MUC" culture="en-US" uiculture="en-US" os-architecture="x64" />
<settings>
<setting name="DisposeRunners" value="True" />
</settings>
<properties>
<property name="_PID" value="1852" />
<property name="_APPDOMAIN" value="domain-" />
</properties>
<failure>
<message><![CDATA[One or more child tests had errors]]></message>
</failure>
<test-suite type="TestSuite" id="0-1005" name="TopGearFramework" fullname="TopGearFramework" runstate="Runnable" testcasecount="2" result="Failed" site="Child" start-time="2019-02-21 04:17:28Z" end-time="2019-02-21 04:19:16Z" duration="108.354384" total="2" passed="1" failed="1" warnings="0" inconclusive="0" skipped="0" asserts="14">
<failure>
<message><![CDATA[One or more child tests had errors]]></message>
</failure>
<test-suite type="TestSuite" id="0-1006" name="CFTestCases" fullname="TopGearFramework.CFTestCases" runstate="Runnable" testcasecount="2" result="Failed" site="Child" start-time="2019-02-21 04:17:28Z" end-time="2019-02-21 04:19:16Z" duration="108.353019" total="2" passed="1" failed="1" warnings="0" inconclusive="0" skipped="0" asserts="14">
<failure>
<message><![CDATA[One or more child tests had errors]]></message>
</failure>
<test-suite type="TestSuite" id="0-1007" name="PoCTestCases" fullname="TopGearFramework.CFTestCases.PoCTestCases" runstate="Runnable" testcasecount="2" result="Failed" site="Child" start-time="2019-02-21 04:17:28Z" end-time="2019-02-21 04:19:16Z" duration="108.352989" total="2" passed="1" failed="1" warnings="0" inconclusive="0" skipped="0" asserts="14">
<failure>
<message><![CDATA[One or more child tests had errors]]></message>
</failure>
<test-suite type="TestSuite" id="0-1008" name="FeatureFiles" fullname="TopGearFramework.CFTestCases.PoCTestCases.FeatureFiles" runstate="Runnable" testcasecount="2" result="Failed" site="Child" start-time="2019-02-21 04:17:28Z" end-time="2019-02-21 04:19:16Z" duration="108.352968" total="2" passed="1" failed="1" warnings="0" inconclusive="0" skipped="0" asserts="14">
<failure>
<message><![CDATA[One or more child tests had errors]]></message>
</failure>
<test-suite type="TestFixture" id="0-1002" name="IndividualDealerPartyCreationFeature" fullname="TopGearFramework.CFTestCases.PoCTestCases.FeatureFiles.IndividualDealerPartyCreationFeature" classname="TopGearFramework.CFTestCases.PoCTestCases.FeatureFiles.IndividualDealerPartyCreationFeature" runstate="Runnable" testcasecount="1" result="Passed" start-time="2019-02-21 04:17:28Z" end-time="2019-02-21 04:19:07Z" duration="99.414157" total="1" passed="1" failed="0" warnings="0" inconclusive="0" skipped="0" asserts="10">
<properties>
<property name="Description" value="Individual Dealer Party Creation" />
</properties>
<output><![CDATA[-> Using app.config
]]></output>
<test-case id="0-1003" name="XF_PAM_004_CheckNewDealerPartyCreationForIndividual" fullname="TopGearFramework.CFTestCases.PoCTestCases.FeatureFiles.IndividualDealerPartyCreationFeature.XF_PAM_004_CheckNewDealerPartyCreationForIndividual" methodname="XF_PAM_004_CheckNewDealerPartyCreationForIndividual" classname="TopGearFramework.CFTestCases.PoCTestCases.FeatureFiles.IndividualDealerPartyCreationFeature" runstate="Runnable" seed="293675085" result="Passed" start-time="2019-02-21 04:17:29Z" end-time="2019-02-21 04:19:07Z" duration="98.585096" asserts="10">
<properties>
<property name="Description" value="XF_PAM_004_Check New Dealer Party Creation for Individual" />
</properties>
<output><![CDATA[Given Browser is launched
-> done: IndividualDealerPartyCreationSteps.GivenBrowserIsLaunched() (0.0s)
]]></output>
<attachments>
<attachment>
<filePath>C:\Users\qxm5789\.jenkins\workspace\TopGearTestRunner_master\TestResults\\XF_PAM_004_Check New Dealer Party Creation for Individual2019-02-21-11_19_02.jpg</filePath>
<description><![CDATA[Screenshot captured]]></description>
</attachment>
</attachments>
</test-case>
</test-suite>
<test-suite type="TestFixture" id="0-1000" name="TestOriginationAPIFeature" fullname="TopGearFramework.CFTestCases.PoCTestCases.FeatureFiles.TestOriginationAPIFeature" classname="TopGearFramework.CFTestCases.PoCTestCases.FeatureFiles.TestOriginationAPIFeature" runstate="Runnable" testcasecount="1" result="Failed" site="Child" start-time="2019-02-21 04:19:07Z" end-time="2019-02-21 04:19:16Z" duration="8.923635" total="1" passed="0" failed="1" warnings="0" inconclusive="0" skipped="0" asserts="4">
<properties>
<property name="Description" value="Test Origination API" />
</properties>
<failure>
<message><![CDATA[One or more child tests had errors]]></message>
</failure>
<test-case id="0-1001" name="FE_AHA_040_SearchApplicationByApplicationIDThroughOriginationAPI" fullname="TopGearFramework.CFTestCases.PoCTestCases.FeatureFiles.TestOriginationAPIFeature.FE_AHA_040_SearchApplicationByApplicationIDThroughOriginationAPI" methodname="FE_AHA_040_SearchApplicationByApplicationIDThroughOriginationAPI" classname="TopGearFramework.CFTestCases.PoCTestCases.FeatureFiles.TestOriginationAPIFeature" runstate="Runnable" seed="2107869277" result="Failed" start-time="2019-02-21 04:19:07Z" end-time="2019-02-21 04:19:16Z" duration="8.921560" asserts="4">
<properties>
<property name="Description" value="FE_AHA_040_Search Application By Application ID through Origination API" />
</properties>
<failure>
<message><![CDATA[ Error Occured:
Expected: <empty>
But was: < "Contract ID 12345 not found." >
]]></message>
<stack-trace><![CDATA[
]]></stack-trace>
</failure>
<output><![CDATA[
]]></output>
<assertions>
<assertion result="Failed">
<message><![CDATA[ Error Occured:
Expected: <empty>
But was: < "Contract ID 12345 not found." >
]]></message>
<stack-trace><![CDATA[
]]></stack-trace>
</assertion>
</assertions>
</test-case>
</test-suite>
</test-suite>
</test-suite>
</test-suite>
</test-suite>
</test-suite>
</test-run>
If you want to get all <test-case> nodes in any depth in XML then XDocument.Descendants("test-case") will do this for you.
And by using LINQ you can retrieve attribute result from each <test-case> node and message from <failure> node if present inside <test-case> node.
Then below code gives you a list of failure message with the result.
class Program
{
public static void Main(string[] args)
{
XDocument doc = XDocument.Load(#"Path to your xml file");
var result = (from t in doc.Descendants("test-case")
from f in t.Descendants("failure")
select new
{
Result = t.Attribute("result").Value,
Failure_Message = f.Element("message") != null ? f.Element("message").Value : ""
}).ToList();
//---------------Print the result------------------
foreach (var item in result)
{
Console.WriteLine("Result: " + item.Result);
Console.WriteLine("Message: " + item.Failure_Message);
}
Console.ReadLine();
}
Output:
You need a custom parser. I used xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication100
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
Testrun testrun = new Testrun();
testrun.ParseXml(FILENAME);
}
}
public class Testrun
{
public string Commandline { get; set; }
public Testsuite Testsuite { get; set; }
public void ParseXml(string filename)
{
XDocument doc = XDocument.Load(filename);
XElement Testrun = doc.Root;
Commandline = (string)Testrun.Element("command-line");
XElement testsuit = Testrun.Element("test-suite");
if (testsuit != null)
{
Testsuite = new Testsuite(testsuit);
}
}
}
public class Testsuite
{
public Attributes attributes { get; set; }
public Testsuite testsuite { get; set; }
public string failure_message { get; set; }
public string property_name { get; set; }
public string property_value { get; set; }
public TestCase TestCase { get; set; }
public Testsuite(XElement xTestsuite)
{
attributes = new Attributes(xTestsuite);
XElement failure = xTestsuite.Element("failure");
if (failure != null) failure_message = (string)failure.Element("message");
XElement properties = xTestsuite.Element("properties");
if (properties != null)
{
XElement property = properties.Element("property");
property_name = (string)property.Attribute("name");
property_value = (string)property.Attribute("value");
}
XElement testcase = xTestsuite.Element("test-case");
if (testcase != null)
{
TestCase = new TestCase(testcase);
}
xTestsuite = xTestsuite.Element("test-suite");
if (xTestsuite != null)
{
testsuite = new Testsuite(xTestsuite);
}
}
}
public class TestCase
{
public string output { get; set; }
public string property_name { get; set; }
public string property_value { get; set; }
public string attachment_filePath { get; set; }
public string attachment_description { get; set; }
public TestCase(XElement testCase)
{
XElement xOutput = testCase.Element("output");
if (xOutput != null) output = (string)xOutput;
XElement properties = testCase.Element("properties");
if (properties != null)
{
XElement property = properties.Element("property");
property_name = (string)property.Attribute("name");
property_value = (string)property.Attribute("value");
}
XElement attachments = testCase.Element("attachments");
if (attachments != null)
{
XElement attachment = attachments.Element("attachment");
attachment_filePath = (string)attachment.Element("filePath");
attachment_description = (string)attachment.Element ("description");
}
}
}
public class Attributes
{
string testtype { get; set; }
string id { get; set; }
string name { get; set; }
string fullname { get; set; }
string runstate { get; set; }
int testcasecount { get; set; }
string result { get; set; }
string site { get; set; }
DateTime start_time { get; set; }
DateTime end_time { get; set; }
decimal duration { get; set; }
int total { get; set; }
int passed { get; set; }
int failed { get; set; }
int warnings { get; set; }
int inconclusive { get; set; }
int skipped { get; set; }
int asserts { get; set; }
public Attributes(XElement attributes)
{
testtype = (string)attributes.Attribute("type");
id = (string)attributes.Attribute("id");
name = (string)attributes.Attribute("name");
fullname = (string)attributes.Attribute("fullname");
runstate = (string)attributes.Attribute("runstate");
testcasecount = (int)attributes.Attribute("testcasecount");
result = (string)attributes.Attribute("result");
site = (string)attributes.Attribute("site");
start_time = (DateTime)attributes.Attribute("start-time");
end_time = (DateTime)attributes.Attribute("end-time");
duration = (decimal)attributes.Attribute("duration");
total = (int)attributes.Attribute("total");
passed = (int)attributes.Attribute("passed");
failed = (int)attributes.Attribute("failed");
warnings = (int)attributes.Attribute("warnings");
inconclusive = (int)attributes.Attribute("inconclusive");
skipped = (int)attributes.Attribute("skipped");
asserts = (int)attributes.Attribute("asserts");
}
}
}

XML serialize multiple elements with same name without namespace

I have the following class which I'm trying to serialize. And I have two arrays with the same data type. I know that if we need more than one element to have the same name the namespace has be different. But there a workaround to remove those namespaces altogether.
[XmlRoot]
public class Album
{
public string Title { get; set; }
public string Description { get; set;}
public int CoverImgIndx { get; set; }
[XmlElement(ElementName ="Element", Namespace ="www.image.com")]
public Image[] Images { get; set; }
[XmlElement(ElementName ="Element", Namespace ="www.cover.com")]
public Image[] Cover { get; set; }
}
public class Image
{
public int indx { get; set; }
public string filepath { get; set; }
}
And I'm using XmlSerializer to serialize this.
public class Program
{
public static void Main()
{
var album = new Album
{
Title = "Album Title",
Description = "Some explanation.",
CoverImgIndx = 2,
Images = new Image[] {
new Image { indx = 0, filepath = #"C:\Images\file1.jpg" },
new Image { indx = 1, filepath = #"C:\Images\file2.png" },
new Image { indx = 2, filepath = #"C:\Images\file3.jpg" }
},
Cover = new Image[] {
new Image { indx = 0, filepath = #"C:\Images\cover1.jpg" }
}
};
XmlSerializer serializer = new XmlSerializer(typeof(Album));
serializer.Serialize(Console.Out, album);
}
}
The output i'm getting there is a namespace for image element. is there way to remove namespace without having to remove Images and Cover shareing the same element name.
<?xml version="1.0" encoding="utf-16"?>
<Album xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Title>Album Title</Title>
<Description>Some explanation.</Description>
<CoverImgIndx>2</CoverImgIndx>
<Element xmlns="www.image.com">
<indx>0</indx>
<filepath>C:\Images\file1.jpg</filepath>
</Element>
<Element xmlns="www.image.com">
<indx>1</indx>
<filepath>C:\Images\file2.png</filepath>
</Element>
<Element xmlns="www.image.com">
<indx>2</indx>
<filepath>C:\Images\file3.jpg</filepath>
</Element>
<Element xmlns="www.cover.com">
<indx>0</indx>
<filepath>C:\Images\cover1.jpg</filepath>
</Element>
</Album>
The output i'm looking for
<?xml version="1.0" encoding="utf-16"?>
<Album xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Title>Album Title</Title>
<Description>Some explanation.</Description>
<CoverImgIndx>2</CoverImgIndx>
<Element>
<indx>0</indx>
<filepath>C:\Images\file1.jpg</filepath>
</Element>
<Element>
<indx>1</indx>
<filepath>C:\Images\file2.png</filepath>
</Element>
<Element>
<indx>2</indx>
<filepath>C:\Images\file3.jpg</filepath>
</Element>
<Element>
<indx>0</indx>
<filepath>C:\Images\cover1.jpg</filepath>
</Element>
</Album>

Multiple, identical elements in the same C# DTO

I am trying to create a WCF-service, which can return me an XML document looking something like this:
<alert>
<identifier>SecretID</identifier>
<info>
<valueName>Name1</valueName>
<value>Info1</value>
</info>
<info>
<valueName>Name2</valueName>
<value>Info2</value>
</info>
</alert>
The DTO of this file would look something like this:
[DataContract(Name = "alert", Namespace = "")]
public class Alert
{
[DataMember(Name = "identifier")]
public string identifier { get; set; }
[DataMember(Name = "info")]
public List<Info> Info { get; set; }
}
[DataContract(Name = "info", Namespace = "")]
public class Info
{
[DataMember(Name = "valueName")]
public string ValueName { get; set; }
[DataMember(Name = "value")]
public string Value { get; set; }
}
However, when I try with the following:
var alert = new Alert()
{
Identifier = "SecretID",
Info = new List<Info>
{
new Info() {ValueName = "Name1", Value = "Info1"},
new Info() {ValueName = "Name2", Value = "Info2"},
}
}
I get:
<alert>
<identifier>SecretID</identifier>
<info>
<info xmlns="">
<valueName>Name1</valueName>
<value>Info1</value>
</info>
<info xmlns="">
<valueName>Name2</valueName>
<value>Info2</value>
</info>
</info>
</alert>
I don't need the extra <info> tag, and the namespace xmlns="" would be nice to have removed too. What should I do to get rid of it?
You can use dictionary or key value pairs as mentioned below:
[DataContract(Name = "alert", Namespace = "")]
public class Alert
{
[DataMember(Name = "identifier")]
public string identifier { get; set; }
[DataMember(Name = "info")]
public KeyValuePair<string, string> Info { get; set; }
}
var alert = new Alert()
{
Identifier = "SecretID",
Info = new KeyValuePair<string, string>()
}

Deserialization returns empty objects

I want to desirialize an XML file to C# Objects. My objects are as follows
[Serializable]
[XmlRoot(ElementName = "Collection")]
public class Collection
{
public Collection()
{
Artiesten = new List<Artiest>();
Albums = new List<Album>();
Nummers = new List<Nummer>();
}
[XmlElement("Artiesten")]
public List<Artiest> Artiesten { get; set; }
[XmlElement("Albums")]
public List<Album> Albums { get; set; }
[XmlElement("Nummers")]
public List<Nummer> Nummers { get; set; }
}
[Serializable]
public class Artiest
{
[XmlAttribute("artiestid")]
public int ArtiestId { get; set; }
[XmlElement(ElementName = "Naam")]
public String Naam { get; set; }
[XmlElement(ElementName = "Albums")]
public List<Album> Albums { get; set; }
}
[Serializable]
public class Nummer
{
[XmlAttribute("nummerid")]
public int NummerId { get; set; }
[XmlElement(ElementName = "titel")]
public String Titel { get; set; }
[XmlElement(ElementName = "duur")]
public String Duration { get; set; }
}
My XML is this:
<Collection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Artiesten>
<Artiest artiestid="1">
<Naam>Harry</Naam>
<Albums>
<Album albumid="1">
<Titel>Album1</Titel>
<prijs valuta="Euro">19.99</prijs>
<uitgiftejaar>1999</uitgiftejaar>
<Nummers>
<Nummer nummerid="1">
<titel>happy Sundays</titel>
<duur>PT02M02S</duur>
</Nummer>
</Nummers>
</Album>
</Albums>
</Artiest>
</Artiesten>
<Albums>
<Album albumid="1">
<Titel>Album1</Titel>
<prijs valuta="Euro">19.99</prijs>
<uitgiftejaar>1999</uitgiftejaar>
<Nummers>
<Nummer nummerid="1">
<titel>Happy Sundays</titel>
<duur>PT02M02S</duur>
</Nummer>
</Nummers>
</Album>
</Albums>
<Nummers>
<Nummer nummerid="1">
<titel>Happy Sundays</titel>
<duur>PT02M02S</duur>
</Nummer>
</Nummers>
</Collection>
And I'm trying to desirialize like this:
XDocument doc = XDocument.Load(file);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Collection));
using (var reader = doc.Root.CreateReader())
{
Collection collection = (Collection) xmlSerializer.Deserialize(reader);
}
For some reason I can't find the lists in the Collection object are all empty. Debugging shows that the loaded file in XDocument is valid.
EDIT: I managed to narrow down the problem. It does deserialize the lists correctly, only all property's of the Objects in those lists are empty.
Found my answer
I had to edit My list Attributes to this:
[XmlElement("Artiesten", typeof(List<Artiest>))]
public List<Artiest> Artiesten { get; set; }
[XmlElement("Albums", typeof(List<Album>))]
public List<Album> Albums { get; set; }
[XmlElement("Nummers", typeof(List<Nummer>))]
public List<Nummer> Nummers { get; set; }
Collection collection = null;
string path = "file.xml";
XmlSerializer serializer = new XmlSerializer(typeof(Collection));
StreamReader reader = new StreamReader(path);
collection = (Collection)serializer.Deserialize(reader);
reader.Close();
You need to re move the [XmlElement] tags from your lists. Otherwise it works with a different XML structure.
For example, rather than nest all your Artiest objects within a single Artiesten element (which is what your current XML is), it will actually set them adjacent to each other like this:
<Artiesten artiestid="1">
<Naam>Harry</Naam>
<Albums>
<Album albumid="1">
<Titel>Album1</Titel>
<prijs valuta="Euro">19.99</prijs>
<uitgiftejaar>1999</uitgiftejaar>
<Nummers>
<Nummer nummerid="1">
<titel>happy Sundays</titel>
<duur>PT02M02S</duur>
</Nummer>
</Nummers>
</Album>
</Albums>
</Artiesten>
<Artiesten artiestid="2">
<Naam>Harry</Naam>
<Albums>
<Album albumid="1">
<Titel>Album1</Titel>
<prijs valuta="Euro">19.99</prijs>
<uitgiftejaar>1999</uitgiftejaar>
<Nummers>
<Nummer nummerid="1">
<titel>happy Sundays</titel>
<duur>PT02M02S</duur>
</Nummer>
</Nummers>
</Album>
</Albums>
</Artiesten>
<Artiesten artiestid="3">
<Naam>Harry</Naam>
<Albums>
<Album albumid="1">
<Titel>Album1</Titel>
<prijs valuta="Euro">19.99</prijs>
<uitgiftejaar>1999</uitgiftejaar>
<Nummers>
<Nummer nummerid="1">
<titel>happy Sundays</titel>
<duur>PT02M02S</duur>
</Nummer>
</Nummers>
</Album>
</Albums>
</Artiesten>
So try redefining your classes as such:
[Serializable]
[XmlRoot(ElementName = "Collection")]
public class Collection
{
public Collection()
{
Artiesten = new List<Artiest>();
Albums = new List<Album>();
Nummers = new List<Nummer>();
}
public List<Artiest> Artiesten { get; set; }
public List<Album> Albums { get; set; }
public List<Nummer> Nummers { get; set; }
}
[Serializable]
public class Artiest
{
[XmlAttribute("artiestid")]
public int ArtiestId { get; set; }
[XmlElement(ElementName = "Naam")]
public String Naam { get; set; }
public List<Album> Albums { get; set; }
}
You want XmlArray, not XmlElement:
[XmlArray("Artiesten")]
[XmlArrayItem("Artiest")]
public List<Artiest> ...
Actually this is the default behaviour for lists, so you also just remove the attribute completely.

Deserializing XML file

Here's how I started:
System.Xml.Serialization.XmlRootAttribute xRoot = new System.Xml.Serialization.XmlRootAttribute();
xRoot.IsNullable = true;
xRoot.Namespace = "urn:schemas-microsoft-com:rowset";
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(ProductSalesList), xRoot);
System.Xml.XmlReader reader = new System.Xml.XmlTextReader(path + "\\" + file);
eltOnly e = (eltOnly)serializer.Deserialize(reader);
But I don't know how to continue. Here's the xml file:
<xml xmlns:s='uuid:00000000-6DA3-11d1-A2A3-00AA00C14882'
xmlns:dt='uuid:C2F41010-0000-11d1-A29F-00AA00C14882'
xmlns:rs='urn:schemas-microsoft-com:rowset'
xmlns:z='#RowsetSchema'>
<s:Schema id='RowsetSchema'>
<s:ElementType name='row' content='eltOnly'>
<s:AttributeType name='Art' rs:number='1' rs:nullable='true' rs:maydefer='true' rs:writeunknown='true'>
<s:datatype dt:type='string' dt:maxLength='255'/>
</s:AttributeType>
<s:AttributeType name='Name' rs:number='2' rs:nullable='true' rs:maydefer='true' rs:writeunknown='true'>
<s:datatype dt:type='string' dt:maxLength='255'/>
</s:AttributeType>
<s:AttributeType name='Sum' rs:number='3' rs:nullable='true' rs:maydefer='true' rs:writeunknown='true'>
<s:datatype dt:type='float' dt:maxLength='8' rs:precision='15' rs:fixedlength='true'/>
</s:AttributeType>
<s:AttributeType name='Cost' rs:number='4' rs:nullable='true' rs:maydefer='true' rs:writeunknown='true'>
<s:datatype dt:type='float' dt:maxLength='8' rs:precision='15' rs:fixedlength='true'/>
</s:AttributeType>
<s:extends type='rs:rowbase'/>
</s:ElementType>
</s:Schema>
<rs:data>
<z:row Art='0000000001' Name='Brand pils 0,2' Sum='153' Cost='304'/>
<z:row Art='0000000002' Name='Brand pils 0,25' Sum='11' Cost='25.300000000000004'/>
<z:row Art='0000000003' Name='Brand pils 0,5' Sum='3' Cost='13.799999999999999'/>
</rs:data>
</xml>
How to continue? How should I call the class which would have the Deserialization attribute?
Here's what I did:
[Serializable()]
public class Elt
{
[System.Xml.Serialization.XmlElement]
public string Art { get; set; }
[System.Xml.Serialization.XmlElement]
public string Name { get; set; }
[System.Xml.Serialization.XmlElement]
public float? Sum { get; set; }
[System.Xml.Serialization.XmlElement]
public float? Cost { get; set; }
}
[Serializable, System.Xml.Serialization.XmlRoot("eltOnly")]
public class eltOnly
{
[System.Xml.Serialization.XmlElement]
public List<Elt> Elt { get; set; }
}
And I get error: There is an error in XML document (1, 2). " was not expected."
This linq2xml should do what you want...
XDocument doc=XDocument.Load(yourXml);
XNamespace rs="urn:schemas-microsoft-com:rowset";
XNamespace z="#RowsetSchema";
var lstRows=doc.Descendants(rs+"data").Elements(z+"row").Select(x=>
new
{
art=x.Attribute("Art").Value,
name=x.Attribute("Name").Value,
sum=(float?)x.Attribute("Sum"),
cost=(float?)x.Attribute("Cost")
}
);
You can now iterate over lstRows
foreach(var row in lstRows)
{
row.art;//string
row.name;//string
row.sum;//float?
row.cost;//float?
}

Categories

Resources