C# - Array from XML as an embedded resource - c#

I've been trying to find a good clean way to load the contents of an XML file into an array to use but I've only found partial answers here and there. My XML file is an Embedded Resource for simplicity, and contains a list of about 115 elements that all contain an id and name attribute.
The XML looks like so:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Items xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Item>
<id>1</id>
<name>Example1</name>
</Item>
<Item>
<id>2</id>
<name>Example2</name>
</Item>
<Item>
<id>3</id>
<name>Example3</name>
</Item>
</Items>
I'm able to load everything in and I see my data in the InnerXML but I cannot find out how to access it correctly.
public Form1()
{
InitializeComponent();
assembly = Assembly.GetExecutingAssembly();
XmlDocument xml = null;
try
{
string filePath = "MyProject.ItemList.xml";
Stream fileStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(filePath);
if (fileStream != null)
{
xml = new XmlDocument();
xml.Load(fileStream);
}
}
catch {
//Do nothing
}
XmlDocument itemsFromXML = xml.DocumentElement.InnerXml;
foreach (XmlNode node in itemsFromXML)
{
int id = Convert.ToInt32(node.Attributes.GetNamedItem("id").ToString());
string name = node.Attributes.GetNamedItem("name").ToString();
gameItemList.Add(new GameItem(id, name));
}
}
That's the code I have that would ideally set this array up for me to use, though it is fairly broken due to me trying different things, but I think it conveys the general idea. Hopefully someone can make some sense of it and explain to me what I'm doing horribly wrong (>.<) I would be happy to provide more information, clarification, etc if I missed something important!
Thanks!

Using System.Xml.Linq:
var items = XElement.Load(fileStream)
.Elements("Item")
.Select(itemXml => new {
id = (int)itemXml.Element("id").Value,
name = itemXml.Element("name").Value
})
.ToArray();

Use an xpath.
XmlNodeList nodes = xml.SelectNodes("Items/Item");
foreach ( XmlNode node in nodes )
{
int id = int.Parse(node.SelectSingleNode("id").InnerText);
}

Related

XML select single node not returning anything

I have the following method that is supposed to return a string that holds the calories for a given food item in an xml menu.
public string calorieCount(int choice)
{
string calCount = "250";
XmlDocument doc = new XmlDocument();
doc.Load(path);
XmlElement root = doc.DocumentElement;
XmlNode node = doc.SelectSingleNode("/menu/item[#name='Burger']/calories");
string checker = node.Value;
MessageBox.Show(checker);//returning nothing
return checker;
}
And my XML file looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<menu>
<!-- Burger -->
<item name="Burger">
<name>Burger</name>
<price>$5.99</price>
<calories>500</calories>
<description>A burger made with 100% angus beef and grilled to your liking. Served with fries</description>
<count>25</count>
</item>
Why is it returning an empty string? Is my call to SelectSingleNode incorrect?
Thank you in advance.
Use InnerText instead of Value
Replace
string checker = node.Value;
With
string checker = node.InnerText;

Using XmlTextReader to Loop though XML attributes that have the same name

I am doing some practice code with the XmlTextReader. I have written some very basic XML as shown here:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<task name="mixed_sprite_task_test">
<sprite>
<type>animatedSprite</type>
<id>0</id>
<name>animatedSprite</name>
<fileName>iyezoz</fileName>
<startingPositionX>200</startingPositionX>
<startingPositionY>200</startingPositionY>
<sheetSizeX>12</sheetSizeX>
<sheetSizeY>35</sheetSizeY>
<startingFrameX>0</startingFrameX>
<startingFrameY>0</startingFrameY>
<startingState>standing</startingState>
<movementSpeed>15</movementSpeed>
<frameDelay>0.055</frameDelay>
</sprite>
<sprite>
<type>staticSprite</type>
<id>0</id>
<name>staticSprite</name>
<fileName>Super_Mario_63</fileName>
<startingPositionX>0</startingPositionX>
<startingPositionY>0</startingPositionY>
</sprite>
<sprite>
<type>simpleSprite</type>
<id>0</id>
<name>simpleSprite</name>
<fileName>imgres</fileName>
<startingPositionX>100</startingPositionX>
<startingPositionY>100</startingPositionY>
<movementSpeed>15</movementSpeed>
</sprite>
</task>
This file shows that I have a task. In the task I have 3 sprites.
In my code I want to loop through each sprite and collect the information.
I can get the data from the first sprite with no issue. Is there a certain way to loop through an xml with attributes of the same name?
Thank-you!
I prefer Linq2Xml.
var xDoc = XDocument.Parse(xmlstring); //or XDocument.Load(filename);
var sprites = xDoc.Descendants("sprite")
.Select(s=>s.Elements()
.ToDictionary(e=>e.Name.LocalName,e=>(string)e))
.ToList();
You can use it as
var type = sprites[0]["type"];
or can take a safe action
string delay;
if (sprites[1].TryGetValue("frameDelay", out delay))
{
Console.WriteLine(delay);
}
You can select all the nodes named "sprite"
var myXml = new XmlDocument();
myXml.Load(myDocument);
XmlNode rootElement = myXml.DocumentElement;
foreach (XmlNode item in rootElement.SelectNodes(#"/task/sprite"))
{
// do stuff with node
}

Extract nodes from XmlNodeList, with namespace, and where same child appears at multiple levels

I am trying to extract those subnodes, but I had got just headache so far...
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<supplyCrew xmlns="http://site.ddf.com">
<login>
<login>XXXX</login>
<password>XXXX</password>
</login>
<flightInformation>
<flights>
<item>
<arrivalDateTime>2010-11-08T22:48:00.000Z</arrivalDateTime>
<arrivingCity>ORD</arrivingCity>
<crewMembers>
<item>
<employeeId>020040</employeeId>
<isDepositor>Y</isDepositor>
<isTransmitter>N</isTransmitter>
</item>
<item>
<employeeId>09000</employeeId>
<isDepositor>N</isDepositor>
<isTransmitter>Y</isTransmitter>
</item>
</crewMembers>
</item>
<item>
<arrivalDateTime>2010-11-08T20:29:00.000Z</arrivalDateTime>
<arrivingCity>JFK</arrivingCity>
<crewMembers>
<item>
<employeeId>0538</employeeId>
<isDepositor>Y</isDepositor>
<isTransmitter>N</isTransmitter>
</item>
<item>
<employeeId>097790</employeeId>
<isDepositor>N</isDepositor>
<isTransmitter>Y</isTransmitter>
</item>
with the code I can get them, but I do not know how to select each one according to their tag name to insert them into a database.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("C:/Crew_Request_Sample.xml");
XmlNodeList elemList = xmlDoc.GetElementsByTagName("item");
foreach (XmlNode node in elemList)
{
Debug.WriteLine(node.InnerText);
}
I need some direction, please.
The problem with using GetElementsByTagName("item") here is that there are 2 levels of item node - one as a child of flights and another item as a child of crewMembers.
Edit Now that the full xml is pasted, it is clear that there is also a namespace involved as well. To handle namespaces, make use of a namespace manager to define aliases for the namespaces, which you can then use in the xpath queries:
var nsm = new XmlNamespaceManager(xmlDoc.NameTable);
nsm.AddNamespace("s", "http://site.ddf.com");
var elemList = xmlDoc.SelectNodes("//s:crewMembers/s:item", nsm);
foreach (var node in elemList)
{
Debug.WriteLine(node.SelectSingleNode("s:employeeId", nsm).InnerText);
Debug.WriteLine(node.SelectSingleNode("s:isDepositor", nsm).InnerText);
Debug.WriteLine(node.SelectSingleNode("s:isTransmitter", nsm).InnerText);
}
You can do it using LINQ2XML..
XElement doc=XElement.Load("C:/Crew_Request_Sample.xml");
XNamespace e = "http://schemas.xmlsoap.org/soap/envelope/";
XNamespace s = "http://site.ddf.com";
//this would access the nodes of item->crewMembers->item and put it into an Anonymous Type
var yourList=doc.Descendants(e+"Body")
.Descendants(s+"supplyCrew")
.Descendants(s+"flightInformation")
.Descendants(s+"flights")
.Descendants(s+"item")
.Descendants(s+"crewMembers")
.Descendants(s+"item")
.Select(
x=>new
{
//Anonymous Type
employeeId=x.Element(s+"employeeId").Value,
isDepositor=x.Element(s+"isDepositor").Value,
isTransmitter=x.Element(s+"isTransmitter").Value
}
);
You can then access yourList using for-each loop
foreach(var item in yourList)
{
Console.WriteLine(item.employeeId);
Console.WriteLine(item.isDepositor);
Console.WriteLine(item.isTransmitter);
}
I think you'll do it faster and easily using this technique
Linq To XML
There is a lot of examples in the site, so it 'll be easy to find what you want.
Hope it helps.

Dataset.WriteXml() namespace and prefix

I have a DataSet with data that I output (write) to an XMl file.
I have added a namespace and prefix to the dataset like this:
public static string XmlNamespace = "http://namespace";
public static string XmlPrefix = "ns0";
RequestDataSet.Namespace = XmlNamespace;
RequestDataSet.Prefix = XmlPrefix;
The XML output is as follows:
<?xml version="1.0" standalone="yes"?>
<ns0:list xmlns:ns0="http://namespace">
<ns0:item xmlns="http://namespace">
<data1>1234</data1>
<data2>91011</data2>
</item>
</ns0:list>
But it should be like this: (no namespace on the item records. Just the prefix)
<?xml version="1.0" standalone="yes"?>
<ns0:list xmlns:ns0="http://namespace">
<ns0:item>
<data1>1234</data1>
<data2>91011</data2>
</item>
</ns0:list>
I have tried setting the tables prefix/namespace to null like this:
RequestDataSet.Tables["item"].Prefix = XmlPrefix;
RequestDataSet.Tables["item"].Namespace = null;
But that also does not work... Does anyone know a solution for this?
I've come across similar issues when fighting with BizTalk adapters... but that's a different story.
Not sure if there is a different (cleaner) way, but you could always 'grab' the attribute and remove it, as decribed here.
Effectively you would do the following:
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(xml);
if (xDoc.DocumentElement.Attributes.Count > 0)
{
XmlAttribute xAtt = xDoc.DocumentElement.Attributes[0];
xDoc.DocumentElement.Attributes.Remove(xAtt);

Reading and navigating an XML dataset file

The XML dataset file after I add it to a DataSet looks like this:
<?xml version="1.0" standalone="yes"?>
<root>
<Email></Email>
<FirstName></FirstName>
<LastName></LastName>
<Addresses>
<item>
<Address1></Address1>
</item>
<item>
<Address1></Address1>
</item>
</Addresses>
<Friends>
<item>
<Name></Name>
</item>
<item>
<Name></Name>
</item>
</Friends>
</root>
I am having issues accessing the Address1 field or the Name field. I can loop through the Addresses or Friends tables but that doesn't help me since the data I want is wrapped one more level down.
I tried this:
foreach (DataRow ar in ds.Tables["Addresses"].Rows)
{
DataRow[] orderDetails = ar.GetChildRows("item");
}
But no success.
Help appreciated.
Thanks
using linq to XML
public static XDocument GetXDocument()
{
XDocument mydata = XDocument.Parse("<?xml version=\"1.0\" standalone=\"yes\"?><root><Email></Email><FirstName></FirstName><LastName></LastName><Addresses><item><Address1>TestData</Address1></item><item><Address1></Address1></item></Addresses> <Friends> <item> <Name></Name> </item><item><Name></Name></item></Friends></root>");
return mydata;
}
this gets the data as a XDocument and this is how you deal with the data
public void OutputAddress()
{
XDocument data = xmlData.GetXDocument();
string Expected = "TestData";
var result = from
addesses in data.Element("root").Elements("Addresses")
where
addesses.Element("item").Element("Address1").Value != string.Empty
select addesses.Element("item").Element("Address1").Value;
foreach (string address1 in result)
{
Console.Write(address1);
}
}
I suggest you use an object wrapper whenever working with XML. This is very eashy to do, I suggest you have a look at this blog:
http://www.picnet.com.au/blogs/Guido/post/2009/09/10/XML-Settings-Files-No-more-webconfig.aspx
Which is aimed at settings XML files however it still applies here.
Thanks
Guido Tapia

Categories