Using XmlAttributeOverrides to change element names in object tree - c#

I need to figure out how to rename elements and/or attributes in generated XML using values retrieved from the database as my element names.
For instance, here is a potential XML output from my current process:
<ArrayOfEntityTreeBase xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<EntityTreeBase EntityInfo="User">
<Children>
<EntityTreeBase EntityInfo="User Medication">
<Properties>
<EntityProperty CreatedDate="2013-11-14T16:41:12.75">
<FieldName>Medication Name</FieldName>
<Value>Celebrex</Value>
</EntityProperty>
<EntityProperty CreatedDate="2013-12-04T14:08:58.597">
<FieldName>Medication Dosage</FieldName>
<Value>20000MG</Value>
</EntityProperty>
<EntityProperty CreatedDate="2013-11-14T16:41:12.76">
<FieldName>Medication Prescribed Date</FieldName>
<Value>08/01/2013</Value>
</EntityProperty>
</Properties>
</EntityTreeBase>
<EntityTreeBase EntityInfo="User Medication">
<Properties>
<EntityProperty CreatedDate="2013-11-14T16:41:12.767">
<FieldName>Medication Name</FieldName>
<Value>Aspirin</Value>
</EntityProperty>
<EntityProperty CreatedDate="2013-11-14T16:41:12.77">
<FieldName>Medication Dosage</FieldName>
<Value>5 mg</Value>
</EntityProperty>
<EntityProperty CreatedDate="2013-11-14T16:41:12.78">
<FieldName>Medication Prescribed Date</FieldName>
<Value>09/01/2013</Value>
</EntityProperty>
</Properties>
</EntityTreeBase>
<EntityTreeBase EntityInfo="User Medication">
<Properties>
<EntityProperty CreatedDate="2013-11-14T16:41:12.783">
<FieldName>Medication Name</FieldName>
<Value>Celebrex</Value>
</EntityProperty>
<EntityProperty CreatedDate="2013-11-14T16:41:12.793">
<FieldName>Medication Dosage</FieldName>
<Value>50 mg twice a day</Value>
</EntityProperty>
<EntityProperty CreatedDate="2013-11-14T16:41:12.8">
<FieldName>Medication Prescribed Date</FieldName>
<Value>10/01/2013</Value>
</EntityProperty>
</Properties>
</EntityTreeBase>
</Children>
<Properties>
<EntityProperty CreatedDate="2013-12-03T13:48:03.45">
<FieldName>User First Name</FieldName>
<Value>John</Value>
</EntityProperty>
<EntityProperty CreatedDate="2013-12-03T11:36:31.423">
<FieldName>User MI</FieldName>
<Value>Q</Value>
</EntityProperty>
<EntityProperty CreatedDate="2013-11-19T09:56:44.66">
<FieldName>User Last Name</FieldName>
<Value>Public</Value>
</EntityProperty>
<EntityProperty CreatedDate="2013-11-14T16:41:12.803">
<FieldName>User SSN</FieldName>
<Value>111-22-3333</Value>
</EntityProperty>
</Properties>
</EntityTreeBase>
</ArrayOfEntityTreeBase>
What I need to accomplish is this:
<UserInformation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<User>
<UserMedications>
<UserMedication>
<MedicationProperties>
<MedicationProperty CreatedDate="2013-11-14T16:41:12.75">
<FieldName>Medication Name</FieldName>
<Value>Celebrex</Value>
</MedicationProperty>
<MedicationProperty CreatedDate="2013-12-04T14:08:58.597">
<FieldName>Medication Dosage</FieldName>
<Value>20000MG</Value>
</MedicationProperty>
<MedicationProperty CreatedDate="2013-11-14T16:41:12.76">
<FieldName>Medication Prescribed Date</FieldName>
<Value>08/01/2013</Value>
</MedicationProperty>
</MedicationProperties>
</UserMedication>
<UserMedication>
<MedicationProperties>
<MedicationProperty CreatedDate="2013-11-14T16:41:12.767">
<FieldName>Medication Name</FieldName>
<Value>Aspirin</Value>
</MedicationProperty>
<MedicationProperty CreatedDate="2013-11-14T16:41:12.77">
<FieldName>Medication Dosage</FieldName>
<Value>5 mg</Value>
</MedicationProperty>
<MedicationProperty CreatedDate="2013-11-14T16:41:12.78">
<FieldName>Medication Prescribed Date</FieldName>
<Value>09/01/2013</Value>
</MedicationProperty>
</MedicationProperties>
</UserMedication>
<UserMedication>
<MedicationProperties>
<MedicationProperty CreatedDate="2013-11-14T16:41:12.783">
<FieldName>Medication Name</FieldName>
<Value>Celebrex</Value>
</MedicationProperty>
<MedicationProperty CreatedDate="2013-11-14T16:41:12.793">
<FieldName>Medication Dosage</FieldName>
<Value>50 mg twice a day</Value>
</MedicationProperty>
<MedicationProperty CreatedDate="2013-11-14T16:41:12.8">
<FieldName>Medication Prescribed Date</FieldName>
<Value>10/01/2013</Value>
</MedicationProperty>
</MedicationProperties>
</UserMedication>
</UserMedications>
<UserProperties>
<UserProperty CreatedDate="2013-12-03T13:48:03.45">
<FieldName>User First Name</FieldName>
<Value>John</Value>
</UserProperty>
<UserProperty CreatedDate="2013-12-03T11:36:31.423">
<FieldName>User MI</FieldName>
<Value>Q</Value>
</UserProperty>
<UserProperty CreatedDate="2013-11-19T09:56:44.66">
<FieldName>User Last Name</FieldName>
<Value>Public</Value>
</UserProperty>
<UserProperty CreatedDate="2013-11-14T16:41:12.803">
<FieldName>User SSN</FieldName>
<Value>111-22-3333</Value>
</UserProperty>
</UserProperties>
</User>
</UserInformation>
Here are my objects:
public class EntityProperty
{
[XmlIgnore]
public int FieldId { get; set; }
public string FieldName { get; set; }
[XmlIgnore]
public int FieldSortOrder { get; set; }
[XmlAttribute()]
public DateTime CreatedDate { get; set; }
[XmlIgnore]
public bool IsIterative { get; set; }
public string Value { get; set; }
public EntityTreeBase Entity { get; set; }
public EntityProperty() { }
public EntityProperty(int fieldId, string fieldName, int fieldSortOrder, DateTime createdDate, bool isIterative, string valueIn)
{
FieldId = fieldId;
FieldName = FieldName;
FieldSortOrder = fieldSortOrder;
CreatedDate = createdDate;
IsIterative = isIterative;
Value = valueIn;
}
}
public class EntityTreeBase
{
[XmlIgnore]
public long EntityId { get; set; }
[XmlIgnore]
public long? ParentEntityId { get; set; }
[XmlIgnore]
public int EntityDefinitionId { get; set; }
[XmlIgnore]
public int DestinationId { get; set; }
[XmlIgnore]
public int Level { get; set; }
[XmlAttribute("EntityInfo")]
public string EntityDefinitionName { get; set; }
public EntityTreeBaseCollection Children { get; set; }
public EntityPropertiesCollection Properties { get; set; }
public EntityTreeBase() { }
public EntityTreeBase(long entityId, long? parentEntityId, int entityDefinitionId, int destinationId, int level, string entityDefinitionName)
{
EntityId = entityId;
ParentEntityId = parentEntityId;
EntityDefinitionId = entityDefinitionId;
DestinationId = destinationId;
Level = level;
EntityDefinitionName = entityDefinitionName;
}
public bool HasChildren
{
get { return (Children != null && Children.Count > 0); }
}
public bool HasProperties
{
get { return (Properties != null && Properties.Count > 0); }
}
public static EntityTreeBase BuildTree(EntityTreeBaseCollection collection, EntityTreeBase parent)
{
parent.Properties = EntityPropertiesCollection.GetProperties(parent.DestinationId, parent.EntityId, parent.EntityDefinitionId);
parent.Children = new EntityTreeBaseCollection();
foreach (EntityTreeBase item in EntityTreeBaseCollection.FindChildEntities(collection, parent.EntityId))
{
parent.Children.Add(BuildTree(EntityTreeBaseCollection.GetChildren(item.EntityId, item.Level, item.DestinationId), item));
}
if (!parent.HasChildren)
{
parent.Children = null;
}
if (!parent.HasProperties)
{
parent.Properties = null;
}
return parent;
}
}
So, as is hopefully obvious, there are no object types named "Medication" or "User", these must be inferred from the data. So I need to know how to use values from the data to change my element names, but I need to figure out how to crawl the object tree so each element name is changed based on the associated EntityDefinitionName. I'm using recursion to populate my object tree prior to serialization. I know the following code works to rename my XmlRoot:
XmlAttributeOverrides xmlOverrides = new XmlAttributeOverrides();
XmlAttributes attribs = new XmlAttributes();
XmlRootAttribute rootAttr = new XmlRootAttribute();
rootAttr.ElementName = collection.Find(e => e.Level == 1).EntityDefinitionName.Replace(" ", "");
attribs.XmlRoot = rootAttr;
But I need to figure out how to change each element name based on the EntityDefinitionName associated with that element or node.
Thanks in advance!

Although I think you can achieve that by using custom serialization I want to present a different approach to solving your question by using an XSLT stylesheet.
This stylesheet transforms your input xml to your desired output xml:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="ArrayOfEntityTreeBase">
<UserInformation >
<xsl:apply-templates />
</UserInformation>
</xsl:template>
<xsl:template match="EntityTreeBase[#EntityInfo='User']">
<User>
<xsl:apply-templates />
</User>
</xsl:template>
<xsl:template match="Children">
<UserMedications>
<xsl:apply-templates />
</UserMedications>
</xsl:template>
<xsl:template match="EntityTreeBase[#EntityInfo='User Medication']">
<UserMedication>
<xsl:apply-templates />
</UserMedication>
</xsl:template>
<xsl:template match="EntityTreeBase[#EntityInfo='User Medication']/Properties">
<MedicationProperties>
<xsl:apply-templates />
</MedicationProperties>
</xsl:template>
<xsl:template match="EntityTreeBase[#EntityInfo='User']/Properties">
<UserProperties>
<xsl:apply-templates/>
</UserProperties>
</xsl:template>
<xsl:template match="EntityTreeBase[#EntityInfo='User']/Properties/EntityProperty">
<xsl:element name="UserProperty">
<xsl:copy-of select="#*"/>
<xsl:copy-of select="*" />
</xsl:element>
</xsl:template>
<xsl:template match="EntityTreeBase[#EntityInfo='User Medication']/Properties/EntityProperty">
<xsl:element name="MedicationProperty">
<xsl:copy-of select="#*"/>
<xsl:copy-of select="*" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
This is the code that you can use the run the transformation in your c# code:
var xml = File.Open("input.xml", FileMode.Open); // or any stream
var xslTrans = new XslCompiledTransform();
xslTrans.Load(XmlReader.Create(File.Open("yourxslfile.xlst", FileMode.Open)));
var output = File.Create("output.xml"); // or a stream
var xw = XmlWriter.Create(output);
xslTrans.Transform(XmlReader.Create(xml), xw );
xw.Close();

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");
}
}
}

XmlDocument - How to get all values from multiple nodes

Here is my sample XML file:
<Main>
<Person>
<Name>Božena</Name>
<Surname>Němcová</Surname>
<Gender>Female</Gender>
<OrderNum>18</OrderNum>
<BirthDate>04.02.1820</BirthDate>
</Person>
<Person>
<Name>Jan</Name>
<Surname>Žižka</Surname>
<Gender>Male</Gender>
<OrderNum>7</OrderNum>
<BirthDate>19.09.1360</BirthDate>
</Person>
<Person>
<Name>Che</Name>
<Surname>Guevara</Surname>
<Gender>Male</Gender>
<OrderNum>27</OrderNum>
<BirthDate>14.06.1928</BirthDate>
</Person>
<Person>
<Name>Antonie</Name>
<Surname>de Saint-Exupéry</Surname>
<Gender>Male</Gender>
<OrderNum>15</OrderNum>
<BirthDate>29.06.1900</BirthDate>
</Person>
</Main>
Here is a code which I want to use to get a list of all values of Name element:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("PersonWrite.xml");
XmlNodeList data = xmlDoc.SelectNodes("Main/Person/Name");
The problem is that I'm only getting a value from the first Person element.
I like using deserialisation, it's a lot easier to work with.
using System;
using System.Xml.Serialization;
using System.IO;
public class Main
{
[XmlElement("Person")]
public Person[] People { get; set; }
}
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
public string Gender { get; set; }
public int OrderNum { get; set; }
public string BirthDate { get; set; }
}
public class Program
{
public static void Main()
{
var xmlString = #"<Main>
<Person>
<Name>Božena</Name>
<Surname>Němcová</Surname>
<Gender>Female</Gender>
<OrderNum>18</OrderNum>
<BirthDate>04.02.1820</BirthDate>
</Person>
<Person>
<Name>Jan</Name>
<Surname>Žižka</Surname>
<Gender>Male</Gender>
<OrderNum>7</OrderNum>
<BirthDate>19.09.1360</BirthDate>
</Person>
<Person>
<Name>Che</Name>
<Surname>Guevara</Surname>
<Gender>Male</Gender>
<OrderNum>27</OrderNum>
<BirthDate>14.06.1928</BirthDate>
</Person>
<Person>
<Name>Antonie</Name>
<Surname>de Saint-Exupéry</Surname>
<Gender>Male</Gender>
<OrderNum>15</OrderNum>
<BirthDate>29.06.1900</BirthDate>
</Person>
</Main>";
var serializer = new XmlSerializer(typeof (Main));
Main main = null;
using (var reader = new StringReader(xmlString))
{
main = (Main)serializer.Deserialize(reader);
}
if (main == null)
{
return;
}
Console.WriteLine(main.People.Length);
}
}
Output:
4
I would go through the Child Nodes of Main Node
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("PersonWrite.xml");
XmlNodeList root = xmlDoc.SelectNodes("Main");
foreach (XmlNode xnode in root.ChildNodes)
{
//get data from xnode
}

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>

Displaying a class list on the main static void

I'm looking to output the list that I've made and usually I just do a for each loop and call up the list like shown in the code below. The console wants me to correct it but then it doesn't display as the reference is null.
Thanks for any help
class Program
{
const string FILENAME = #"royalTreeResults.xml";
// THIS SECTION OF CODE IS WHAT IT SUGGESTS private static readonly IEnumerable<Family> families;
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
Tree tree = new Tree();
tree.families = doc.Descendants("family").Select(x => new Family()
{
FamilyName = (string)x.Element("name"),
FamilyTotalReign = (int)x.Element("totalReign"),
People = x.Elements("person").Select(y => Person.Recursive(y)).ToList()
}).ToList();
foreach(Family per in families) // <--- THE ERROR IS HERE
{
Console.WriteLine(per.FamilyName + " " + per.FamilyTotalReign + " " + per.People);
}
}
}
public class Family
{
public string FamilyName { get; set; }
public int FamilyTotalReign { get; set; }
public List<Person> People { get; set; }
}
public class Person
{
public int? PersonBorn { get; set; }
public int? PersonCoronation { get; set; }
public int? PersonDied { get; set; }
public string PersonName { get; set; }
public int? PersonYinPower { get; set; }
public List<Person> Children { get; set; }
public static Person Recursive(XElement person)
{
Person newPerson = new Person();
newPerson.PersonName = (string)person.Element("name");
newPerson.PersonYinPower = (int?)person.Element("yearsInpower");
newPerson.PersonBorn = (int?)person.Element("born");
newPerson.PersonDied = (int?)person.Element("died");
newPerson.PersonCoronation = (int?)person.Element("coronation");
if (person.Element("children") != null)
{
newPerson.Children = person.Element("children").Elements("person").Select(y => Person.Recursive(y)).ToList();
}
return newPerson;
}
}
public class Tree
{
public List<Family> families = new List<Family>();
}
A sample of the .xml is below, however I know this is not the problem
<?xml version="1.0" encoding="utf-8"?>
<royaltree>
<family>
<name>Wessex</name>
<totalReign>137</totalReign>
<person>
<name>Alfred the Great</name>
<yearsInpower>28</yearsInpower>
<born>849</born>
<died>899</died>
<coronation>871</coronation>
<children>
<person>
<name>Edward the Elder</name>
<yearsInpower>25</yearsInpower>
<born>879</born>
<died>924</died>
<coronation>899</coronation>
<children>
<person>
<name>Edmund I the Elder</name>
<yearsInpower>6</yearsInpower>
<born>939</born>
<died>946</died>
<coronation>940</coronation>
<children>
<person>
<name>Edger the Peaceful</name>
<yearsInpower>16</yearsInpower>
<born>944</born>
<died>975</died>
<coronation>959</coronation>
<children>
<person>
<name>Ethelred II</name>
<yearsInpower>38</yearsInpower>
<born>962</born>
<died>1016</died>
<coronation>978</coronation>
<children>
<person>
<name>Edward Confessor</name>
<yearsInpower>24</yearsInpower>
<born>1002</born>
<died>1066</died>
<coronation>1042</coronation>
</person>
<person>
<name>Edward II Ironside</name>
<yearsInpower>0</yearsInpower>
<born>1002</born>
<died>1016</died>
<coronation>1016</coronation>
</person>
</children>
</person>
</children>
</person>
</children>
</person>
</children>
</person>
</children>
</person>
</family>
<family>
<name>Norman</name>
<totalReign>69</totalReign>
<person>
<name>William I</name>
<yearsInpower>21</yearsInpower>
<born>1028</born>
<died>1087</died>
<coronation>1066</coronation>
<children>
<person>
<name>Adela</name>
<born>1050</born>
<died>1080</died>
</person>
<person>
<name>William II</name>
<yearsInpower>13</yearsInpower>
<born>1056</born>
<died>1100</died>
<coronation>1087</coronation>
</person>
<person>
<name>Henry I Beauclerc</name>
<yearsInpower>35</yearsInpower>
<born>1068</born>
<died>1135</died>
<coronation>1100</coronation>
<children>
<person>
<name>Matilda</name>
<born>1130</born>
<died>1167</died>
</person>
</children>
</person>
</children>
</person>
</family>
I don't know if I get you right. But I hope this might be helpful:
static void Main(string[] args)
{
//... your stuff
//Iterate through families in tree
foreach (Family per in tree.families)
{
//Show the family info
Console.WriteLine(per.FamilyName + " " + per.FamilyTotalReign);
//Show the members recursively
ShowPeopleRecursive(per.People, 1);
}
}
//Shows the people tree.
private static void ShowPeopleRecursive(List<Person> people, int level)
{
const string indent = "";
foreach (var p in people)
{
Console.WriteLine($"{indent.PadLeft(level, ' ')} {p.PersonName} ({p.PersonBorn} - {p.PersonDied}). Years in power: {p.PersonYinPower}");
if (p.Children != null)
ShowPeopleRecursive(p.Children, level + 1);
}
}
You iterate over your families in the tree and then recursively print the people (and their children). You should see something like:
Hope this helps!
So you have to loop through you person list like below.
foreach (Family per in tree.families) // <--- THE ERROR IS HERE
{
Console.WriteLine(per.FamilyName + " " + per.FamilyTotalReign);
foreach (var ppl in per.People)
{
Console.WriteLine(ppl.PersonName + " " + per.FamilyName);
}
}
But I would like to recommend you to use XmlSerializer and you can Deserialize your XML to object.This is much more cleaner approach. if you want sample code let me know.

Linq to Xml selecting elements

I have this xml file:
<?xml version="1.0" encoding="utf-8" ?>
<Calendar>
<item id="34">
<Date>26 Apr</Date>
<Name>aa</Name>
<Date>26 Apr</Date>
<Name>aaa</Name>
<Date>23 Apr</Date>
<Name>aaaa</Name>
<Date>23 Apr</Date>
<Name>aaaaa</Name>
</item>
<item id="35">
<Date>27 Apr</Date>
<Name>aa</Name>
<Date>27 Apr</Date>
<Name>aaa</Name>
<Date>27 Apr</Date>
<Name>aaaa</Name>
<Date>27 Apr</Date>
<Name>aaaaa</Name>
</item>
</Calendar>
this is my class
public class Calendar
{
public string Name{ get; set; }
public string Data { get; set; }
}
listBox.ItemsSource =
from var in xml.Descendants("item")
orderby Convert.ToInt32(var.Attribute("id").Value) ascending
select new Calendar
{
Name= var.Element("Name").Value,
Data = var.Element("Data ").Value,
};
but in listBox i have only the first date and name of every item
class Program
{
static void Main(string[] args)
{
XDocument xml =
XDocument.Load(
#"Path to your xml");
var q = from x in xml.Descendants("item")
orderby Convert.ToInt32(x.Attribute("id").Value) ascending
select new Calendar
{
Name = x.Elements("Name").Select(a => a.Value).ToList<String>(),
Date = x.Elements("Date").Select(a => a.Value).ToList<String>()
};
List<Calendar> calendars = q.ToList<Calendar>();
}
public class Calendar
{
public List<String> Name { get; set; }
public List<String> Date { get; set; }
}
}
XElement.Element(elementName) only gets the first element that matches the elementName. Try a different approach using XElement.Elements(elementName)

Categories

Resources