how to create Nested XML in C# - c#

I want to create nested xml so that the result would look like:
<?xml version=\"1.0\" encoding=\"UTF-8\"?><TASKLOADLOG>
<PERSON>
<EMAIL>data</EMAIL><LOADED>OK</LOADED><LOADERROR>ABC</LOADERROR>
</PERSON>
<PERSON>
<EMAIL>data</EMAIL><LOADED>OK</LOADED><LOADERROR>ABC</LOADERROR>
</PERSON>
<PERSON>
<EMAIL>data</EMAIL><LOADED>OK</LOADED><LOADERROR>ABC</LOADERROR>
</PERSON>
</TASKLOADLOG>"
I wrote following code and It crashed in a loop
XmlDocument XmlResponse = new XmlDocument();
XmlDeclaration xDeclare = XmlResponse.CreateXmlDeclaration("1.0", "UTF-8", null);
XmlElement documentRoot = XmlResponse.DocumentElement;
XmlResponse.InsertBefore(xDeclare, documentRoot);
XmlElement el = (XmlElement)XmlResponse.AppendChild(XmlResponse.CreateElement("TASKLOADLOG"));
List<XmlElement> ls = new List<XmlElement>();
for (int i = 0; i < 3; i++)
{
ls[i].AppendChild(XmlResponse.CreateElement("EMAIL")).InnerText = "data";
ls[i].AppendChild(XmlResponse.CreateElement("LOADED")).InnerText = "OK";
ls[i].AppendChild(XmlResponse.CreateElement("LOADERROR")).InnerText = "ABC";
}
MessageBox.Show(XmlResponse.OuterXml);
I don't now how to define PERSON what I need to write to fix my code?

The problem is simple, you are not creating the PERSON node. Email, Loaded and LoadError should be child nodes to Person node.
Edit:
just to let you know, you could even use class Serialization for the XML you are trying to generate.
For Example:
[Serializable]
public class Person
{
[XmlAttribute]
public string Email { get; set; }
public string Loaded { get; set; }
public string LoadError{ get; set; }
}
Person p = new Person
{
Email = "abc",
Loaded = "abc";
LoadError = "abc"
};
new XmlSerializer(typeof(Person)).Serialize(Console.Out, Person);

thanks about the quick answer
I wrote following code and It got error in XmlResponse.Root.AppendChild :
XmlDocument XmlResponse = new XmlDocument();
XmlDeclaration xDeclare = XmlResponse.CreateXmlDeclaration("1.0", "UTF-8", null);
XmlElement documentRoot = XmlResponse.DocumentElement;
XmlResponse.InsertBefore(xDeclare, documentRoot);
XmlElement el = (XmlElement)XmlResponse.AppendChild(XmlResponse.CreateElement("TASKLOADLOG"));
//List<XmlElement> ls = new List<XmlElement>();
for (int i = 0; i < 3; i++)
{
XmlResponse.Root.AppendChild(new XElement("PERSON",
new XElement("EMAIL", "data"),
new XElement("LOADED", "OK"),
new XElement("LOADERROR", "ABC")
)));
}
MessageBox.Show(XmlResponse.OuterXml);

Your code is crashing because you are referencing the first index of your list ls when the list is empty.
Create your document like this:
var doc = XDocument(new XElement("TASKLOADLOG"));
for (int i = 0; i < 3; i++)
doc.Root.AppendChild(new XElement("PERSON",
new XElement("EMAIL", "data"),
new XElement("LOADED", "OK"),
new XElement("LOADERROR", "ABC")
)));
}

Related

How do I get a specific element in a XML document?

I have a XML file that looks like this:
<Info>
<ID>1</ID>
<Result>
<ID>2</ID>
</Result>
</Info>
I want to count how many Info/Result/ID I have in this file.
I am doing this:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("myFile.xml");
xmlNodeList MyList = xmlDoc.GetElementsByTagName("Info/Result/ID");
int totalCount = MyList.Count;
// other logic...
The method GetElementsByTagName does not find any "ID"-field.
I want to get the "ID = 2".
How do I do that?
To count all the nodes in "Info/Result/ID" path use this..
var count = xmlDoc.SelectNodes("Info/Result/ID")?.Count ?? 0;
To process these nodes
var nodes = xmlDoc.SelectNodes("Info/Result/ID");
foreach (XmlNode node in nodes) {
var idValue = node.InnerText
// do something
}
Got it working, hereĀ“s how:
public static void MyCountExample(string myXml, out int myID)
{
var stream = new MemoryStream(Encoding.UTF8.GetBytes(myXml ?? ""));
var reader = XmlReader.Create(stream);
myID= 0;
reader.IsStartElement("Info");
while (!reader.EOF)
{
if (reader.ReadToFollowing("Result"))
{
if (reader.ReadToDescendant("ID"))
{
myID++;
else
{
return somethingElse();
}
......

merging 2 xml records with the same schema

How do we merge 2 XML records that have the same schema?
For example let's say we have two records such as :
<msg>
<name>alex</name>
<payload></payload>
</msg>
and the second:
<msg>
<name></name>
<payload>blabla</payload>
</msg>
The expected result:
<msg>
<name>alex</name>
<payload>blabla</payload>
</msg>
We simply took the non-empty value.
How do we merge two xml records with the same schema?
A simple implementation would just go though the elements pairing corresponding items by name and create a new element choosing the text of the non-blank element.
XElement ShallowMerge(XElement a, XElement b) =>
new XElement(a.Name,
from ae in a.Elements()
join be in b.Elements() on ae.Name equals be.Name
select new XElement(ae.Name,
!String.IsNullOrWhiteSpace((string)ae)
? (string)ae
: (string)be
)
);
//two lists for temp storing .xml data
List<Person> list1= new List<Person>();
List<Person> list2= new List<Person>();
List<Person> list3= new List<Person>();//for mixing
string path=#"c:\.....";
//properties of .xml notes like 'name' and 'payload'
public class Person
{
public string name{ get; set; }//1
public string payload{ get; set; }//2
}
//load both .xml files saperatly
void load_list1()
{
XmlDocument xdoc = new XmlDocument();
xdoc.Load(path + #"\list1.xml");
foreach (XmlNode xnode in xdoc.SelectNodes("Items/Item"))
{
Person p = new Person();
p.name= xnode.SelectSingleNode("a").InnerText;
p.payload= xnode.SelectSingleNode("b").InnerText;
list1.Items.Add(p);
}
}
void load_list2()
{
XmlDocument xdoc = new XmlDocument();
xdoc.Load(path + #"\list2.xml");
foreach (XmlNode xnode in xdoc.SelectNodes("Items/Item"))
{
Person p = new Person();
p.name= xnode.SelectSingleNode("a").InnerText;
p.payload= xnode.SelectSingleNode("b").InnerText;
list2.Items.Add(p);
}
}
//start mixing both lists
void mixdata()
{
for(int i=0;i<list1.Items.Count;i++)
{
Person p= new Person();
p.name=list1.Items[i].name;
p.payload=list2.Items[i].payload;
list3.Items.Add(p);
}
}
//saving final mixed list to .xml
void save()
{
XmlDocument xdoc = new XmlDocument();
xdoc.Load(path + #"\Mixed_data.xml");
XmlNode xnode = xdoc.SelectSingleNode("Items");
xnode.RemoveAll();
foreach (Person i in list3)
{
XmlNode xtop = xdoc.CreateElement("Item");
XmlNode x1 = xdoc.CreateElement("a");
XmlNode x2 = xdoc.CreateElement("b");
x1.InnerText = i.name;
x2.InnerText = i.payload;
xtop.AppendChild(x1);
xtop.AppendChild(x2);
xdoc.DocumentElement.AppendChild(xtop);
}
xdoc.Save(path + #"\data.xml");
}
//let me know any errors

Xml Tags get wrong encoded

I'm trying to write a list of objects to valid xml. My code looks basicly like this:
public class Person
{
public string First { get; set; }
public string Last { get; set; }
}
List<Person> people = new List<Person>();
XElement elements = new XElement("People",
from p in people
select new XElement("Person",
new XElement("First", p.First),
new XElement("Last", p.Last)));
string output = elements.ToString();
Unfortunately output when written to a file looks like this:
<People>
<Person>
<First>Tom</First>
<Last>Hanks</Last>
</Person>
</People>
XDeclaration declaration = new XDeclaration("1.0", "utf-8", "yes");
XProcessingInstruction procInstruction = new XProcessingInstruction("xml-stylesheet", "type='text/xsl'");
XElement root = new XElement("Store");
XDocument settingsFile = new XDocument(declaration, procInstruction, root);
foreach (string key in persistentSettings.Keys)
{
string value = persistentSettings[key];
if (!string.IsNullOrEmpty(value))
{
XElement setting = new XElement("Setting", new XAttribute("Name", key));
setting.Value = value;
root.Add(setting);
}
}
settingsFile.Save(SettingsFileName);
What is that I'm doing wrong here?
I had to use the parse function in the Constructor of xElement
XElement setting
= new XElement("Setting", new XAttribute("Name", key), XElement.Parse(value));
instead of
XElement setting = new XElement("Setting", new XAttribute("Name", key));
setting.Value = value;

How to get xml element values using XmlNodeList in c#

I need to store the element values which are inside the nodes "member" . I have tried the following code but I can't achieve it. How to get the values. Any help would be appreciated
XML:
<ListInventorySupplyResponse xmlns="http://mws.amazonaws.com/FulfillmentInventory/2010-10-01/">
<ListInventorySupplyResult>
<InventorySupplyList>
<member>
<SellerSKU>043859634910</SellerSKU>
<FNSKU>X000IA4045</FNSKU>
<ASIN>B005YV4DJO</ASIN>
<Condition>NewItem</Condition>
<TotalSupplyQuantity>7</TotalSupplyQuantity>
<InStockSupplyQuantity>7</InStockSupplyQuantity>
<EarliestAvailability>
<TimepointType>Immediately</TimepointType>
</EarliestAvailability>
<SupplyDetail>
</SupplyDetail>
</member>
</InventorySupplyList>
</ListInventorySupplyResult>
<ResponseMetadata>
<RequestId>58c9f4f4-6f60-496a-8d71-8fe99ce301c9</RequestId>
</ResponseMetadata>
</ListInventorySupplyResponse>
C# Code:
string a = Convert.ToString(oInventorySupplyRes.ToXML());
XmlDocument oXdoc = new XmlDocument();
oXdoc.LoadXml(a);
XmlNodeList oInventorySupplyListxml = oXdoc.SelectNodes("//member");
foreach (XmlNode itmXml in oInventorySupplyListxml)
{
// var cond = itmXml.InnerXml.ToString();
var asinVal = itmXml.SelectSingleNode("ASIN").Value;
var TotalSupplyQuantityVal = itmXml.SelectSingleNode("TotalSupplyQuantity").Value;
}
ResultView : "Enumeration yielded no results" and count = 0;
Edit 1:
string a = Convert.ToString(oInventorySupplyRes.ToXML());
var status = oInventorySupplyResult.InventorySupplyList;
XmlDocument oXdoc = new XmlDocument();
var doc = XDocument.Parse(a);
var r = doc.Descendants("member")
.Select(member => new
{
ASIN = member.Element("ASIN").Value,
TotalSupplyQuantity = member.Element("TotalSupplyQuantity").Value
});
private string mStrXMLStk = Application.StartupPath + "\\Path.xml";
private System.Xml.XmlDocument mXDoc = new XmlDocument();
mXDoc.Load(mStrXMLStk);
XmlNode XNode = mXDoc.SelectSingleNode("/ListInventorySupplyResult/InventorySupplyList/member");
if (XNode != null)
{
int IntChildCount = XNode.ChildNodes.Count;
for (int IntI = 1; IntI <= IntChildCount ; IntI++)
{
string LocalName = XNode.ChildNodes[IntI].LocalName;
XmlNode Node = mXDoc.SelectSingleNode("/Response/" + LocalName);
// Store Value in Array assign value by "Node.InnerText"
}
}
Try This Code. Its Worked
try using this xpath
string xPath ="ListInventorySupplyResponse/ListInventorySupplyResult
/InventorySupplyList/member"
XmlNodeList oInventorySupplyListxml = oXdoc.SelectNodes(xpath);
when you do "//member", then, the code is trying to look for element named member from the root level, which is not present at the root level, rather it is nested beneath few layers.
I think this will help you..
string a = Convert.ToString(oInventorySupplyRes.ToXML());
XmlDocument oXdoc = new XmlDocument();
oXdoc.LoadXml(a);
XmlNodeList fromselectors;
XmlNodeList toselectors;
XmlElement root = oXdoc.DocumentElement;
fromselectors = root.SelectNodes("ListInventorySupplyResult/InventorySupplyList/member/ASIN");
toselectors = root.SelectNodes("ListInventorySupplyResult/InventorySupplyList/member/TotalSupplyQuantity");
foreach (XmlNode m in fromselectors)
{
you will have value in `m.InnerXml` use it whereever you want..
}
foreach (XmlNode n in toselectors)
{
you will have value in `n.InnerXml` use it whereever you want..
}

Help with Linq to XML

Iv got two DB tables. One containing types(Id, Name) and the other holds datapoints (RefId, Date, Value) that are referenced by the types. I need to create a XML file with the following strukture:
<?xml version='1.0' encoding='utf-8' ?>
<root>
<type>
<name></name>
<data>
<date></date>
<temp></temp>
</data>
<data>
<date></date>
<temp></temp>
</data>
<data>
<date></date>
<temp></temp>
</data>
</type>
</root>
And iv got the following code to do this
public XmlDocument HelloWorld()
{
string tmp = "";
try
{
sqlConn.ConnectionString = ConfigurationManager.ConnectionStrings["NorlanderDBConnection"].ConnectionString;
DataContext db = new DataContext(sqlConn.ConnectionString);
Table<DataType> dataTypes = db.GetTable<DataType>();
Table<DataPoints> dataPoints = db.GetTable<DataPoints>();
var dataT =
from t in dataTypes
select t;
var dataP =
from t in dataTypes
join p in dataPoints on t.Id equals p.RefId
select new
{
Id = t.Id,
Name = t.Name,
Date = p.PointDate,
Value = p.PointValue
};
string xmlString = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><root></root>";
XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(xmlString);
int count = 0;
foreach (var dt in dataT)
{
XmlElement type = xmldoc.CreateElement("type");
XmlElement name = xmldoc.CreateElement("name");
XmlNode nameText = xmldoc.CreateTextNode(dt.Name);
name.AppendChild(nameText);
type.AppendChild(name);
foreach(var dp in dataP.Where(dt.Id = dp.RefId))
{
XmlElement data = xmldoc.CreateElement("data");
XmlElement date = xmldoc.CreateElement("date");
XmlElement temp = xmldoc.CreateElement("temp");
XmlNode dateValue = xmldoc.CreateTextNode(dp.Date.ToString());
date.AppendChild(dateValue);
XmlNode tempValue = xmldoc.CreateTextNode(dp.Value.ToString());
temp.AppendChild(tempValue);
data.AppendChild(date);
data.AppendChild(temp);
type.AppendChild(data);
}
xmldoc.DocumentElement.AppendChild(type);
}
return xmldoc;
}
catch(Exception e)
{
tmp = e.ToString();
}
return null;
}
[Table(Name="DataTypes")]
public class DataType
{
[Column(IsPrimaryKey = true)]
public long Id;
[Column]
public string Name;
}
[Table(Name="DataPoints")]
public class DataPoints
{
[Column]
public long RefId;
[Column]
public DateTime PointDate;
[Column]
public double PointValue;
}
This is not a working code. Im having problems with LINQ and the inner joins. Could someone please help me to get the correct strukture. I hope its kinda clear what im trying to achive.
Best Regards
Marthin
var result =
new XDocument(new XElement("root",
from dt in dataTypes
join dp in dataPoints on dt.Id equals dp.RefId
select new XElement("type",
new XElement("name", dt.Name),
new XElement("data",
new XElement("date", dp.PointDate),
new XElement("temp", dp.PointValue)))));
var result =
new XDocument(new XElement("root",
from dt in dataTypes
select new XElement("type",
new XElement("name", dt.Name),
from dp in dataPoints
where dp.RefId == dt.Id
select new XElement("data",
new XElement("date", dp.PointDate),
new XElement("temp", dp.PointValue)))));

Categories

Resources