reading xml using xml parser - c#

I need to get user id corresponding terminal id. any help. But it's giving error:
The ReadElementContentAsString method is not supported on node type
None. Line 1, position 668.
string strTerminalId = "E";
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(STRING); //
string strxml = xdoc.OuterXml;
string strUserName = "";
bool Flag = false;
using (XmlReader reader = XmlReader.Create(new StringReader(strxml)))
{
while (reader.Read())
{
if (reader.IsStartElement())
{
switch (reader.Name)
{
case "Row":
reader.Read();
if (Flag == false)
{
reader.ReadToFollowing("TERM-ID");
reader.Read();
string strTERMID = reader.ReadElementContentAsString().ToString();
if (strTERMID == strTerminalId)
{
while (reader.ReadToFollowing("NA") && (Flag == false))
{
reader.Read();
string strUser = reader.ReadContentAsString();
if (strUser == "NA")
{
reader.ReadToFollowing("c:value");
reader.Read();
strUserName = reader.ReadContentAsString();
Flag = true;
}
}
}
}
break;
}
}
}
The content of the XML document is
<GetReferenceTableResponse xmlns='http://tempuri.org/'>
<GetReferenceTableResult>
<Table Name='C' ID='46899' xmlns=''>
<Columns>
<Col ID='7442' Name='TD' Datatype='T' Length='8' AttributeDescription='Terminal ID' IsKey='Y'/>
<Col ID='7443' Name='D' Datatype='T' Length='50' AttributeDescription='Description' IsKey=' '/>
<Col ID='7444' Name='U' Datatype='T' Length='8' AttributeDescription='USER-ID' IsKey='' />
</Columns>
<Rows>
<Row RowsetID=\"1\">
<TERM-ID ID='279598'>A</TERM-ID>
<DESC-TXT ID='279622'>ASC</DESC-TXT>
<USER-ID ID='279646'>A</USER-ID>
</Row>
</Rows>
</Table>
</GetReferenceTableResult>
</GetReferenceTableResponse>

ReadToFollowing navigates to the nearest element with a given name and the next Read will go inside that element - straight to the Text. So you would need ReadContentAsString in both cases.
In your case that would work:
using (XmlReader reader = XmlReader.Create(new StringReader(strxml)))
{
while (reader.Read())
{
if (reader.IsStartElement())
{
switch (reader.Name)
{
case "Row":
if (!Flag)
{
reader.ReadToFollowing("TERM-ID");
reader.Read();
string strTERMID = reader.ReadContentAsString();
if (strTERMID == strTerminalId && reader.ReadToNextSibling("USER-ID"))
{
reader.Read();
strUserName = reader.ReadContentAsString();
Flag = true;
}
}
break;
}
}
}
}
I have removed the first Read just after case "Row": - otherwise you would miss the proper element and as well removed ReadToFollowing("USER-ID") from the while loop - it is okey to go into the element only once.
But as #kennyzx said - it is much simpler to parse the xml using XDoccument.
UPDATE
I am not sure about your schema but if it is possible for a Row element to not have User-Id, then with ReadToFollowing it is possible to skip to the next available 'User-ID' element, even if it is not in the same 'Row' element. So it is better to use ReadToNextSibling in the second case.

Related

C# xml reader, same element name

I'm trying to read an element from my xml file.
I need to read an string in an "link" element inside the "metadata",
but there are 2 elements called "link", I only need the second one:
<metadata>
<name>visit-2015-02-18.gpx</name>
<desc>February 18, 2015. Corn</desc>
<author>
<name>text</name>
<link href="http://snow.traceup.com/me?id=397760"/>
</author>
<link href="http://snow.traceup.com/stats/u?uId=397760&vId=1196854"/>
<keywords>Trace, text</keywords>
I need to read this line:
<link href="http://snow.traceup.com/stats/u?uId=397760&vId=1196854"/>
This is the working code for the first "link" tag, it works fine,
public string GetID(string path)
{
string id = "";
XmlReader reader = XmlReader.Create(path);
while (reader.Read())
{
if ((reader.NodeType == XmlNodeType.Element) && (reader.Name == "link"))
{
if (reader.HasAttributes)
{
id = reader.GetAttribute("href");
MessageBox.Show(id + "= first id");
return id;
//id = reader.ReadElementContentAsString();
}
}
}
return id;
}
Does anyone know how I can skip the first "link" element?
or check if reader.ReadElementContentAsString() contains "Vid" or something like that?
I hope you can help me.
xpath is the answer :)
XmlReader reader = XmlReader.Create(path);
XmlDocument doc = new XmlDocument();
doc.Load(reader);
XmlNodeList nodes = doc.SelectNodes("metadata/link");
foreach(XmlNode node in nodes)
Console.WriteLine(node.Attributes["href"].Value);
Use the String.Contains method to check if the string contains the desired substring, in this case vId:
public string GetID(string path)
{
XmlReader reader = XmlReader.Create(path);
while (reader.Read())
{
if ((reader.NodeType == XmlNodeType.Element) && (reader.Name == "link"))
{
if (reader.HasAttributes)
{
var id = reader.GetAttribute("href");
if (id.Contains(#"&vId"))
{
MessageBox.Show(id + "= correct id");
return id;
}
}
}
return String.Empty;
}
If acceptable you can also use LINQ2XML:
var reader = XDocument.Load(path); // or XDocument.Parse(path);
// take the outer link
Console.WriteLine(reader.Root.Element("link").Attribute("href").Value);
The output is always:
http://snow.traceup.com/stats/u?uId=397760&vId=1196854= first id
Another options is to use XPath like #user5507337 suggested.
XDocument example:
var xml = XDocument.Load(path); //assuming path points to file
var nodes = xml.Root.Elements("link");
foreach(var node in nodes)
{
var href = node.Attribute("href").Value;
}

Reading XML giving null

<tours xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://api.contiki.com/schemas/v2/detailed_tours.xsd">
<tour>
<id>290</id>
<name>Peru Uncovered</name>
<lowest_price>
<code>11D15a</code>
</lowest_price>
</tour>
</tours>
I want to read Id, name and code.
I am trying this code
XmlTextReader reader = new XmlTextReader(downloadfolder);
XmlDocument doc = new XmlDocument();
XmlNode node = doc.ReadNode(reader);
foreach (XmlNode chldNode in node.ChildNodes)
{
string employeeName = chldNode.Attributes["name"].Value;
}
But i am getting null. Can anyone tell me how can i read the values? i can not use Linq as i am working in SSIS 2008 project which does not support linq.
Updated Answer
XmlTextReader reader = new XmlTextReader(downloadfolder);
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element: // The node is an element.
string node = reader.Name;
if (node == "id")
{
string id = reader.ReadString();
}
if (node == "name")
{
string name = reader.ReadString();
}
if (node == "code")
{
string code = reader.ReadString();
}
break;
}
I can read the values but how can i add these as a row in my data table?
here node type of "name" is element.
below code can be used for node type checking
XmlTextReader reader = new XmlTextReader ("<file name>");
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
Reference : http://support.microsoft.com/en-us/kb/307548

is it possible to detect if an xml node is present using c#?

i have a xml file and i want to know if it is possible to see if the <VertrekVertragingTekst> is present in the xml file.
this is the xml node:
<VertrekkendeTrein>
<RitNummer>4722</RitNummer>
<VertrekTijd>2014-06-03T09:45:00+0200</VertrekTijd>
<VertrekVertraging>PT2M</VertrekVertraging>
<VertrekVertragingTekst>+2 min</VertrekVertragingTekst>
<EindBestemming>Uitgeest</EindBestemming>
<TreinSoort>Sprinter</TreinSoort>
<Vervoerder>NS</Vervoerder>
<VertrekSpoor wijziging="false">2</VertrekSpoor>
</VertrekkendeTrein>
(these nodes are in dutch so dont pay attention to what they say, that is not important)
this is the c# code that i have so far:
XmlNodeList nodeList = xmlDoc.SelectNodes("ActueleVertrekTijden/VertrekkendeTrein/*");
foreach (XmlNode nodelist2 in nodeList)
{
if (i < 1) //1
switch (nodelist2.Name)
{
case "VertrekTijd": string kuttijd1 = (nodelist2.InnerText);
var res1 = Regex.Match(kuttijd1, #"\d{1,2}:\d{1,2}").Value;
lblv1.Text = Convert.ToString(res1); break;
case "VertrekVertragingTekst": ververt1.Text = (nodelist2.InnerText); ververt1.Visible = true; vertpic1.Visible = true; logo1.Top -= 9; lblts1.Top -= 9; break;
case "EindBestemming": string vertrek1 = (nodelist2.InnerText); if (vertrek1 == "Uitgeest") { lblvia1.Text = "Krommenie-Ass"; } lblbs1.Text = vertrek1; break;
case "TreinSoort": lblts1.Text = (nodelist2.InnerText); break;
case "RouteTekst": lblvia1.Text = (nodelist2.InnerText); break;
case "VertrekSpoor": lbls1.Text = (nodelist2.InnerText); i++; break;
}
}
i can read out of this file and everything works but i want to know how i can detect the presence of this node?
Use SelectSingleNode Method
var result = node.SelectSingleNode("nodeTocheck");
if(result!=null)
{
}
It could be done with Linq To Xml based on the following code snippet.
XDocument XmlDoc = XDocument.Parse(Doc);
var Query = XmlDoc.Root.DescendantNodes()
.OfType<XElement>()
.Where(iEl =>iEl.Name.LocalName.Equals("NodeName"));
The sequence would contain all nodes of name NodeName.
I use XmlReader class to read XML files, you can also give it a try
namespace System.Xml.XmlReader
Example:
String xmlString =
#"<bookstore>
<book genre='autobiography' publicationdate='1981-03-22' ISBN='1-861003-11-0'>
<title>The Autobiography of Benjamin Franklin</title>
<author>
<first-name>Benjamin</first-name>
<last-name>Franklin</last-name>
</author>
<price>8.99</price>
</book>
</bookstore>";
// Create an XmlReader
using (XmlReader reader = XmlReader.Create(new StringReader(xmlString)))
{
if(reader.ReadToFollowing("book"))
{
reader.MoveToFirstAttribute();
string genre = reader.Value;
Console.WriteLine("The genre value: " + genre);
}
else
{
//Do something else
}
}
Output
The genre value: autobiography

how to parse XML using XmlReader along with their closing tags?

Consider the following XML which I have to parse.
<root>
<item>
<itemId>001</itemId>
<itemName>test 1</itemName>
<description/>
</item>
</root>
I have to parse each of its tag and store it into a table as follows:
TAG_NAME TAG_VALUE IsContainer
------------ -------------- -----------
root null true
item null true
itemId 001 false
itemName test 1 false
description null false
/item null true
/root null true
Now to get this done, I am using XmlReader as this allows us to parse each & every node.
I am doing it as follows:
I created the following class to contain each tag's data
public class XmlTag
{
public string XML_TAG { get; set; }
public string XML_VALUE { get; set; }
public bool IsContainer { get; set; }
}
I am trying to get the list of tags(including closing ones) as follows:
private static List<XmlTag> ParseXml(string path)
{
var tags = new List<XmlTag>();
using (var reader = XmlReader.Create(path))
{
while (reader.Read())
{
var tag = new XmlTag();
bool shouldAdd = false;
switch (reader.NodeType)
{
case XmlNodeType.Element:
shouldAdd = true;
tag.XML_TAG = reader.Name;
//How do I get the VALUE of current reader?
//How do I determine if the current node contains children nodes to set IsContainer property of XmlTag object?
break;
case XmlNodeType.EndElement:
shouldAdd = true;
tag.XML_TAG = string.Format("/{0}", reader.Name);
tag.XML_VALUE = null;
//How do I determine if the current closing node belongs to a node which had children.. like ROOT or ITEM in above example?
break;
}
if(shouldAdd)
tags.Add(tag);
}
}
return tags;
}
but I am having difficulty determining the following:
How to determine if current ELEMENT contains children XML nodes? To set IsContainer property.
How to get the value of current node value if it is of type XmlNodeType.Element
Edit:
I have tried to use LINQ to XML as follows:
var xdoc = XDocument.Load(#"SampleItem.xml");
var tags = (from t in xdoc.Descendants()
select new XmlTag
{
XML_TAG = t.Name.ToString(),
ML_VALUE = t.HasElements ? null : t.Value,
IsContainer = t.HasElements
}).ToList();
This gives me the XML tags and their values but this does not give me ALL the tags including the closing ones. That's why I decided to try XmlReader. But If I have missed anything in LINQ to XML example, please correct me.
First of all, as noted by Jon Skeet in the comments you should probably consider using other tools, like XmlDocument possibly with LINQ to XML (EDIT: an example with XmlDocument follows).
Having said that, here is the simplest solution for what you have currently (note that it's not the cleanest possible code, and it doesn't have much validation):
private static List<XmlTag> ParseElement(XmlReader reader, XmlTag element)
{
var result = new List<XmlTag>() { element };
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
element.IsContainer = true;
var newTag = new XmlTag() { XML_TAG = reader.Name };
if (reader.IsEmptyElement)
{
result.Add(newTag);
}
else
{
result.AddRange(ParseElement(reader, newTag));
}
break;
case XmlNodeType.Text:
element.XML_VALUE = reader.Value;
break;
case XmlNodeType.EndElement:
if (reader.Name == element.XML_TAG)
{
result.Add(new XmlTag()
{
XML_TAG = string.Format("/{0}", reader.Name),
IsContainer = element.IsContainer
});
}
return result;
}
}
return result;
}
private static List<XmlTag> ParseXml(string path)
{
var result = new List<XmlTag>();
using (var reader = XmlReader.Create(path))
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
result.AddRange(ParseElement(
reader,
new XmlTag() { XML_TAG = reader.Name }));
}
else if (reader.NodeType == XmlNodeType.EndElement)
{
result.Add(new XmlTag()
{
XML_TAG = string.Format("/{0}",current.Name)
});
}
}
}
return result;
}
An example using XmlDocument. This will give slightly different result for self-enclosing tags (<description/> in your case). You can change this behaviour easily, depending on what you want.
private static IEnumerable<XmlTag> ProcessElement(XElement current)
{
if (current.HasElements)
{
yield return new XmlTag()
{
XML_TAG = current.Name.ToString(),
IsContainer = true
};
foreach (var tag in current
.Elements()
.SelectMany(e => ProcessElement(e)))
{
yield return tag;
}
yield return new XmlTag()
{
XML_TAG = string.Format("/{0}", current.Name.ToString()),
IsContainer = true
};
}
else
{
yield return new XmlTag()
{
XML_TAG = current.Name.ToString(),
XML_VALUE = current.Value
};
yield return new XmlTag()
{
XML_TAG = string.Format("/{0}",current.Name.ToString())
};
}
}
And using it:
var xdoc = XDocument.Load(#"test.xml");
var tags = ProcessElement(xdoc.Root).ToList();

Getting the value of XML tag xith XMLReader and add to LinkedList C#

I am a new to programming, and have a serious problem and cant get out of it.
I have 5 XML URLs. such as http://www.shopandmiles.com/xml/3_119_3.xml
This is an XML URL which I have to get values and write to database in related columns.
My column names and XML tag names do match.
When I write the below code, reader element miss null xml values. Some tags do not have value inside. I have to add them null to linkedlist because after that code, i am going through the linked list but the order doesnt match if ı cant add a value for null xml values. So column names and data inside doesnt match. i lose the order. My all code is here, you can also check comment in the code if that helps. Thank you all.
public void WebServiceShopMilesCampaignsXMLRead(string URL)
{
XmlReader reader = XmlReader.Create(URL);
LinkedList<string> linkedList = new LinkedList<string>();
List<ShopAndMilesCampaigns> shopMileCampaigns = new List<ShopAndMilesCampaigns>();
try
{
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Text:
linkedList.AddLast(reader.Value);
break;
}
}
}
catch (XmlException exception)
{
Console.WriteLine("XML okurken bir sorun oluştu, hata detayı --> " + exception.Message);
}
LinkedListNode<string> node = linkedList.First;
while (node != null)
{
ShopAndMilesCampaigns shopMilesCampaign = new ShopAndMilesCampaigns();
shopMilesCampaign.Name = node.Value; // Null values mixes up the order because i cant add as null with reader.read above
node = node.Next;
shopMilesCampaign.Summary = node.Value;
node = node.Next;
shopMilesCampaign.AccountName = node.Value;
node = node.Next;
shopMilesCampaign.Category = node.Value;
node = node.Next;
shopMilesCampaign.Sector = node.Value;
node = node.Next;
shopMilesCampaign.Details = node.Value;
node = node.Next;
shopMilesCampaign.Image = node.Value;
node = node.Next;
shopMilesCampaign.Status = 1;
node = node.Next;
shopMileCampaigns.Add(shopMilesCampaign);
}
foreach (ShopAndMilesCampaigns shopMileCampaign in shopMileCampaigns)
{
shopMileCampaign.Insert();
}
}
I found the answer. Here it is to let you know.
If the XmlNodeType is equal to Element, then the loop continues to read from the XML data and looks for Whitesapces and end Element of XML tag. The below code gives me the exact value of XML tag even it is empty.
public LinkedList<string> AddToLinkedList(XmlReader reader)
{
LinkedList<string> linkedList = new LinkedList<string>();
try
{
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
reader.Read();
Start:
if (reader.NodeType == XmlNodeType.Whitespace || reader.NodeType == XmlNodeType.Element)
{
reader.Read();
goto Start;
}
else if (reader.NodeType == XmlNodeType.EndElement)
{
linkedList.AddLast("");
}
else
{
linkedList.AddLast(reader.Value);
}
break;
}
}
}

Categories

Resources