C#: Creating XML document using Linq having not proper output? - c#

I'm trying to create xml data from my data, creation was successfull but the output is bad how can I fix this issue?
Here is my code:
private void btnGenerate_Click(object sender, EventArgs e)
{
XElement xml = new XElement("Navigation",
new XElement("NavigationSets"));
foreach (DataRow row_navs in GetNavigationSets().Rows)
{
xml.Add(new XElement("NavigationName", row_navs["name"].ToString()));
foreach (DataRow row_sets in GetMenusInNavigationSetByNavigation(2).Rows)
{
if (int.Parse(row_sets["id"].ToString()) == int.Parse(row_navs["id"].ToString()))
{
foreach (DataRow row_menus in GetMenuById(int.Parse(row_sets["menu_id"].ToString())).Rows)
{
xml.Add(new XElement("MenuName", row_menus["name"].ToString()));
}
}
}
}
xml.Save("data.xml");
}
Im expecting an output like this
<?xml version="1.0" encoding="utf-8"?>
<Navigation>
<NavigationSets>
<NavigationName>
<MenuName></MenuName>
</NavigationName>
<NavigationSets/>
</Navigation>
In my current code my output is like this
<?xml version="1.0" encoding="utf-8"?>
<Navigation>
<NavigationSets/>
<NavigationName></NavigationName>
<MenuName></MenuName>
</Navigation>

To add to Jon Skeets answer,
You can also use
using System.Xml.Linq;
to loop through lists so it is all one statement,
new XElement("NavigationSets",
menus.Select(menu => new XElement("MenuName"))
)

Look at when you're adding elements:
xml.Add(new XElement("NavigationName", row_navs["name"].ToString()));
xml.Add(new XElement("MenuName", row_menus["name"].ToString()));
Where xml is this element:
XElement xml = new XElement("Navigation",
new XElement("NavigationSets"));
That means xml is the Navigation element, not the NavigationSets element. I suspect you want something like:
XElement outer = new XElement("Navigation");
XElement inner = new XElement("NavigationSets");
outer.Add(inner);
... then add to inner.

Related

XMLResponse element show in list

I'm doing a HttpWebrequest by using c#. I get the following response
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Siri version="1.0" xmlns="http://www.siri.org.uk/">
<ServiceDelivery>
<ResponseTimestamp>2013-03-21T11:40:13.514Z</ResponseTimestamp>
<StopMonitoringDelivery version="1.0">
<ResponseTimestamp>2013-03-21T11:40:13.514Z</ResponseTimestamp>
<RequestMessageRef>12345</RequestMessageRef>
<MonitoredStopVisit>
<RecordedAtTime>2013-03-21T11:40:13.514Z</RecordedAtTime>
<MonitoringRef>020035811</MonitoringRef>
<MonitoredVehicleJourney>
<FramedVehicleJourneyRef>
<DataFrameRef>-</DataFrameRef>
<DatedVehicleJourneyRef>-</DatedVehicleJourneyRef>
</FramedVehicleJourneyRef>
<VehicleMode>bus</VehicleMode>
<PublishedLineName>1</PublishedLineName>
<DirectionName>Kempston</DirectionName>
<OperatorRef>STB</OperatorRef>
<MonitoredCall>
<AimedDepartureTime>2013-03-21T11:41:00.000Z</AimedDepartureTime>
<ExpectedDepartureTime>2013-03-21T11:44:27.000Z</ExpectedDepartureTime>
</MonitoredCall>
</MonitoredVehicleJourney>
</MonitoredStopVisit>
</StopMonitoringDelivery>
</ServiceDelivery>
</Siri>
This response is saved in a string variable called "ResponseFromServer"
Now I just want to show the 'ExpectedDepartureTime' in a listbox
I tried to do this with the following code:
//XMLResponse put in documentRoot
XDocument documentRoot = XDocument.Parse(responseFromServer);
//Linq To XML
var documents =
(from docs in documentRoot.Descendants("ServiceDelivery").Descendants("StopMonitoringDelivery").Descendants("MonitoredStopVisit").Descendants("MonitoredVehicleJourney").Descendants("MonitoredCall")
select new
{
dep = docs.Element("ExpectedDepartureTime").Value
});
//Show every ExpectedDepartureTime
foreach (var i in documents)
{
lstHours.Items.Add(i);
MessageBox.Show(i.ToString());
}
When I try this nothing happens (the messagebox is not appearing and in the listbox i see nothnig). I also try to Descendant first the tag without success...
Can anybody help me with this issue?
Thanks!
You need to specify namespace like this and then use one method Descendants
XNamespace ns = "http://www.siri.org.uk/";
var documents =
documentRoot.Descendants(ns + "MonitoredCall")
.Select(x => x.Element(ns + "ExpectedDepartureTime").Value);
now you can
foreach (var i in documents)
{
lstHours.Items.Add(i);
MessageBox.Show(i.ToString());
}
prints
2013-03-21T11:44:27.000Z

Please help me find right namespace combination so I can query XML in C#

I have one xml file whic I need to edit, It looks like:
<?xml version="1.0" encoding="UTF-8"?>
<PaketniUvozObrazaca xmlns="urn:PaketniUvozObrazaca_V1_0.xsd">
<PodaciOPoslodavcu>
<JIBPoslodavca>XXXXXXXXXX</JIBPoslodavca>
<NazivPoslodavca>Comapyn</NazivPoslodavca>
<BrojZahtjeva>1307</BrojZahtjeva>
<DatumPodnosenja>2013-03-19</DatumPodnosenja>
</PodaciOPoslodavcu>
<Obrazac1022>
<Dio1PodaciOPoslodavcuIPoreznomObvezniku>
<JIBJMBPoslodavca>XXXXXXXXXX</JIBJMBPoslodavca>
<Naziv>Compyny</Naziv>
<AdresaSjedista>Adress </AdresaSjedista>
<JMBZaposlenika>XXXXXXX</JMBZaposlenika>
<ImeIPrezime>ad</ImeIPrezime>
<AdresaPrebivalista>City</AdresaPrebivalista>
<PoreznaGodina>2012</PoreznaGodina>
</Dio1PodaciOPoslodavcuIPoreznomObvezniku>
</Obrazac1022>
</PaketniUvozObrazaca>
If i want to query (select nodes) from this file how I should reffernce namespace ?
static void Main(string[] args)
{
XmlDocument gip = new XmlDocument();
gip.Load("C:\\vs2013tests\\adoGipko\\gip-2012.xml");
XmlNamespaceManager nspm = new XmlNamespaceManager(gip.NameTable);
nspm.AddNamespace("urn", "PaketniUvozObrazaca_V1_0");
foreach (XmlNode uposlnik in gip.SelectNodes("//PaketniUvozObrazaca_V1_0/Obrazac1022", nspm))
{
Console.WriteLine(uposlnik.SelectSingleNode("Dio1PodaciOPoslodavcuIPoreznomObvezniku/ImeIPrezime",nspm).InnerText);
}
Console.ReadKey();
}
You need to give the namespace a name and specify the uri exactly as in the XML. Which name you use is not important:
nspm.AddNamespace("d", "urn:PaketniUvozObrazaca_V1_0.xsd");
You now have to use that name for all the tags:
foreach (XmlNode uposlnik in gip.SelectNodes("//d:PaketniUvozObrazaca/"+
"d:Obrazac1022", nspm))
{
Console.WriteLine(
uposlnik.SelectSingleNode("d:Dio1PodaciOPoslodavcuIPoreznomObvezniku/"+
"d:ImeIPrezime", nspm).InnerText);
}
Furthermore, I fixed the root tag in the query. You used PaketniUvozObrazaca_V1_0 which is part of the namespace. You need to use PaketniUvozObrazaca, which is the root tag.

Reading XML file via XML nodes

I have this XML document I am trying to read in and insert into a data base. There will only ever be one GamePlay node however GamePlayStep may repeat so I have created a node list for this. For some reason GamePlayStep isn't receiving data. Here is the XML file:
<?xml version="1.0" encoding="utf-8" ?>
<GameData>
<GamePlay>
<type>add</type>
<GamePlayID>1</GamePlayID>
<ParticipantID>1</ParticipantID>
<GameID>1</GameID>
<GameDifficultyID>1</GameDifficultyID>
<Start>2012-08-06T12:19:33.154Z</Start>
<End>2012-08-06T12:30:33.154Z</End>
<Success>False</Success>
</GamePlay>
<GamePlayStep>
<GamePlayStepID>1</GamePlayStepID>
<Start>2012-08-06T12:19:33.154Z</Start>
<End>2012-08-06T12:30:33.154Z</End>
<SortOrder>1</SortOrder>
<Score>1</Score>
<hintUsed>True</hintUsed>
<GamePause>
<GamePauseID>1</GamePauseID>
<Start>2012-08-06T12:19:33.154Z</Start>
<End>2012-08-06T12:30:33.154Z</End>
<Order>1</Order>
<Duration>05:01</Duration>
</GamePause>
</GamePlayStep>
</GameData>
Here is my code:
public static void start()
{
string[] filePaths = Directory.GetFiles(System.Configuration.ConfigurationManager.ConnectionStrings["filePath"].ConnectionString);
List<GamePlay> gameObj = new List<GamePlay>();
List<GamePlayStep> gameStepObj = new List<GamePlayStep>();
foreach (string value in filePaths)
{
XmlDocument xd = new XmlDocument();
XmlNodeList GameSteps;
xd.Load(value);
XmlNode documentNode = xd.SelectSingleNode("/GameData/GamePlay");
GameSteps = xd.SelectNodes("/GameData/GamePlay/GamePlayStep");
GamePlay newGamePlay = new GamePlay();
newGamePlay.setType(Convert.ToString(documentNode.SelectSingleNode("type").InnerText));
newGamePlay.setGamePlayID(Convert.ToInt32(documentNode.SelectSingleNode("GamePlayID").InnerText));
newGamePlay.setParticipantID(Convert.ToInt32(documentNode.SelectSingleNode("ParticipantID").InnerText));
newGamePlay.setGameDifficultyID(Convert.ToInt32(documentNode.SelectSingleNode("GameDifficultyID").InnerText));
newGamePlay.setGameID(Convert.ToInt32(documentNode.SelectSingleNode("GameID").InnerText));
newGamePlay.setStartDateTime(Convert.ToDateTime(documentNode.SelectSingleNode("Start").InnerText));
newGamePlay.setEndDateTime(Convert.ToDateTime(documentNode.SelectSingleNode("End").InnerText));
newGamePlay.setSuccess(Convert.ToBoolean(documentNode.SelectSingleNode("Success").InnerText));
newGamePlay.setFile(value);
newGamePlay.addNewGamePlay();
foreach (XmlNode documentNode2 in GameSteps)
{
GamePlayStep newGamePlayStep = new GamePlayStep();
newGamePlayStep.setGamePlayStepID(Convert.ToInt32(documentNode2.SelectSingleNode("GamePlayStepID").InnerText));
newGamePlayStep.setGamePlayID(newGamePlay.getGamePlayID());
newGamePlayStep.setStartDateTime(Convert.ToDateTime(documentNode2.SelectSingleNode("Start").InnerText));
newGamePlayStep.setEndDateTime(Convert.ToDateTime(documentNode2.SelectSingleNode("End").InnerText));
newGamePlayStep.setOrderPlayed(Convert.ToInt32(documentNode2.SelectSingleNode("SortOrder").InnerText));
newGamePlayStep.setScore(Convert.ToInt32(documentNode2.SelectSingleNode("Score").InnerText));
newGamePlayStep.setHintUsed(Convert.ToBoolean(documentNode2.SelectSingleNode("hintUsed").InnerText));
newGamePlayStep.addNewGamePlayStep();
}
}
}
The GamePlay is filling the variables properly and inserting into the database however the GamePlaySteps in the NodeList are not. Does anyone see the problem or how I can improve this?
Thanks.
Your XPath for accessing the GamePlayStep is incorrect;
It should be:
GameSteps = xd.SelectNodes("/GameData/GamePlayStep");
As GamePlayStep is a child of GameData, not GamePlay, in your document.
Use LINQ2XML....its simple and cool
XElement doc=XElement.Load("yourXml");
newGamePlay.setType(doc.Descendants("GameData").Element("GamePlay").Element("type").Value);
....
foreach (Element eml in doc.Descendants("GameData").Elements("GamePlayStep"))
{
GamePlayStep newGamePlayStep = new GamePlayStep();
newGamePlayStep.setGamePlayStepID(Convert.ToInt32(elm.Element("GamePlayStepID").Value));
newGamePlayStep.setStartDateTime(Convert.ToDateTime(elm.Element("Start").Value));
.....
}

Reading XML File with multiple NS

I am trying to read an XML feed to get the last post date. My xml looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
>
<channel>
<title>mysite</title>
<atom:link href="http://www.mysite.com/news/feed/" rel="self" type="application/rss+xml" />
<link>http://www.mysite.com/news</link>
<description>mysite</description>
<lastBuildDate>Tue, 22 Nov 2011 16:10:27 +0000</lastBuildDate>
<language>en</language>
<sy:updatePeriod>hourly</sy:updatePeriod>
<sy:updateFrequency>1</sy:updateFrequency>
<generator>http://wordpress.org/?v=3.0.4</generator>
<item>
<title>My first post!</title>
<link>http://www.mysite.com/news/2011/11/22/docstore-v2-released/</link>
<comments>http://www.mysite.com/news/2011/11/22/docstore-v2-released/#comments</comments>
<pubDate>Tue, 22 Nov 2011 16:10:27 +0000</pubDate>
<dc:creator>mysite</dc:creator>
<category><![CDATA[News]]></category>
<category><![CDATA[Promotions]]></category>
<category><![CDATA[docstore]]></category>
I didn't show all of the xml since it is rather long.
My method, so far, looks like this:
private void button1_Click(object sender, EventArgs e)
{
var XmlDoc = new XmlDocument();
// setup the XML namespace manager
var mgr = new XmlNamespaceManager(XmlDoc.NameTable);
// add the relevant namespaces to the XML namespace manager
mgr.AddNamespace("ns", "http://purl.org/rss/1.0/modules/content/");
var webClient = new WebClient();
var stream = new MemoryStream(webClient.DownloadData("http://www.mysite.com/news/feed/"));
XmlDoc.Load(stream);
// **USE** the XML anemspace in your XPath !!
XmlElement NodePath = (XmlElement)XmlDoc.SelectSingleNode("/ns:Response");
while (NodePath != null)
{
foreach (XmlNode Xml_Node in NodePath)
{
Console.WriteLine(Xml_Node.Name + ": " + Xml_Node.InnerText);
}
}
}
I'm having a problem with it telling me:
Namespace Manager or XsltContext needed. This query has a prefix,
variable, or user-defined function.
All I want to pull out of this xml code is the 'lastBuildDate'. I'm going in circles trying to get this code right.
Can someone tell me what I am doing wrong here?
Thank you!
You're not using the namespace manager.
// **USE** the XML anemspace in your XPath !!
XmlElement NodePath = (XmlElement)XmlDoc.SelectSingleNode("/ns:Response", mgr);
There is only one of the element you are going after, you could go directly to it using the XPath. That element is also in the default namespace, so you do not need to do anything special to get to it. What about:
var XPATH_BUILD_DATE="/rss/channel/lastBuildDate";
private void button1_Click(object sender, EventArgs e){
var xmlDoc = new XmlDocument();
var webClient = new WebClient();
var stream = new MemoryStream(webClient.DownloadData("http://www.mysite.com/news/feed/"));
xmlDoc.Load(stream);
XmlElement xmlNode = (XmlElement)xmlDoc.SelectSingleNode(XPATH_BUILD_DATE);
Console.WriteLine(xmlNode.Name + ": " + xmlNode.InnerText);
}
If you did however need to dig into elements in a different namespace, you can do that also with the XPath (example, getting the dc:creator:
/rss/channel/item[1]/*[local-name() = 'creator']

Error loading contents from a XML file into a dropdownlist

private void BindCountry()
{
XmlDocument doc = new XmlDocument();
doc.Load(Server.MapPath("countries.xml"));
foreach (XmlNode node in doc.SelectNodes("//country"))
{
usrlocationddl.Items.Add(new ListItem(node.InnerText, node.Attributes["codes"].InnerText));
}
}
The above code am using for loading countries List from an xml file into a dropdown list. But while doing so am encountering a Null Reference error.
Object reference not set to an
instance of an object.
Contents of the xml file:
<countries>
<country code="AF" iso="4">Afghanistan</country>
<country code="AL" iso="8">Albania</country>
</countries>
Where in the code should I be changing, so that I can escape the error.
I suspect the problem is that you've got a country with no "codes" attribute. You could avoid that like this:
private void BindCountry()
{
XmlDocument doc = new XmlDocument();
doc.Load(Server.MapPath("countries.xml"));
foreach (XmlNode node in doc.SelectNodes("//country"))
{
XmlAttribute attr = node.Attributes["codes"];
if (attr != null)
{
usrlocationddl.Items.Add(new ListItem(node.InnerText, attr.Value));
}
}
}
If that doesn't help, I suggest you write a simple console application to try to load the XML and write out each entry you'd select - that should make it easier to work out what's going wrong.

Categories