How to read from an XmlReader without moving it forwards? - c#

I got this scenario:
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element && reader.Name == itemElementName)
{
XElement item = null;
try
{
item = XElement.ReadFrom(reader) as XElement;
}
catch (XmlException ex)
{
//log line number and stuff from XmlException class
}
}
}
In the above loop I'm transforming a certain node (itemElementName) into an XElement.
Some nodes will be good XML and will go into an XElement, however, some will not.
In the CATCH, I'd like to not only catch the standard XmlException stuff... I'd also like to catch an extract of the current Xml and a string.
However, if I do any kind of READ operation on the node before I pass it to the XElement, it moves the reader forward.
How can get a "snapshot" of the contents of the OuterXml of the reader without interfering with it's position?

Actually ReadSubtree will return a reader which "wraps" the original reader. So reading through the new one will end up advancing the original one as well.
You must consider XmlReader as a forward only reader, it simply can't go back.
As for your scenario, instead of trying to remember part of the XML you can ask the reader for the position in the input file. Just cast it to IXmlLineInfo interface, it has methods to return line and position. Using this you could remember some starting position (before the element in question) and then the end position of the error. And then read that part from the intput file as a plain text.

Another idea: read the outer XML (which advances the reader), then create a new reader from this XML which allows you to "go back" and process the elements of the current node.
while (r.ReadToFollowing("ParentNode"))
{
parentXml = r.ReadOuterXml();
//since ReadOuterXml() advances the reader to the next parent node, create a new reader to read the remaining elements of the current parent
XmlReader r2 = XmlReader.Create(new StringReader(parentXml));
r2.ReadToFollowing("ChildNode");
childValue = r2.ReadElementContentAsString();
r2.Close();
}

Don't use any 'Read' operation on the reader- as you've discovered, this advances it. Use calls to properties such as reader.HasValue and reader.Value to inspect the contents. Look up 'XmlReader' in the object browser, there's quite a few properties you can read.
Edit: I don't think there's an easy way of simply getting the XML, possibly because the current node may not be valid XML on it's own, such as an XmlWhiteSpace, XmlText node or even an XmlAttribute.

What I did was read just the element into an XmlDocument, and read that instead. In my case, I had to convert a flow document to HTML. I had to read a inner element to assign a "style" to the parent HTML element.

In fact, although Vitek Karas MSFT is right, Helena Kupkova published a deft little XML Bookmark Reader on https://msdn.microsoft.com/en-us/library/aa302292.aspx. This enables going backwards using caching.

Something like that with ReadSubtree
using (XmlReader reader = XmlReader.Create(new StringReader(xml)))
{
reader.MoveToContent();
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (reader.Name == "Field") // for example i need to read node field
{
XmlReader inner = reader.ReadSubtree(); // the reader stays in the same position
XElement El = XElement.Load(inner) as XElement;
inner.Close();
}
}
}
}

Related

I am having trouble moving data from an XML file into an ARRAY with CDATA node type

As per title am having issues getting data from an XML file with CDATA elements into an array.
Based on my current limited understanding of how to do it, I came up with this basic working method
CDATA is odd so my normal methods didn't work. My normal route of finding the nodes wasn't stopping on them, and then there is the whole CDATA issue.
XmlTextReader xmlReader = new XmlTextReader(FilePath);
while (xmlReader.Read())
{
// Position the reader on the OrderNumber node
xmlReader.ReadToFollowing("quoteNumber");
XmlReader inner = xmlReader.ReadSubtree();
while (inner.Read())
{
switch (xmlReader.NodeType)
{
case XmlNodeType.CDATA:
Globals.COData[0] = inner.Value;
break;
}
}
xmlReader.ReadToFollowing("orderNumber");
inner = xmlReader.ReadSubtree();
while (inner.Read())
{
switch (xmlReader.NodeType)
{
case XmlNodeType.CDATA:
Globals.COData[1] = inner.Value;
break;
}
}
But I have many many data elements to fetch and assume there is a better way. File looks like:
And the relevant portion:
<quoteNumber>
<![CDATA[ John Test 123]]>
</quoteNumber>
<orderNumber>
<![CDATA[ 1352738]]>
</orderNumber>
The item contained does have a closing element at file end. The entire XML is too large to post.
the XML format is not in my control.
My end goal is to get the OrderNumber and its value into an array. And the Quote number and its value. I am used to seeing <OrderNumber>123</OrderNumber> so CDATA nodes are new to me.
It's not entirely clear where you are going wrong because you don't share your complete XML, but you are not checking the return value from XmlReader.ReadToFollowing(string) from inside your Read() loop. Thus, once you read past the last <orderNumber>, you will get an exception when another <quoteNumber> is not found.
I would suggest restructuring your code as follows:
var ns = ""; // Replace with #"http://intelliquip.com/integrationS..." can't see the full namespace from the XML image.
var list = new List<Tuple<string, string>>(); // List of (quoteNumber, orderNumber) values.
var xmlReader = XmlReader.Create(FilePath);
while (xmlReader.ReadToFollowing("quoteNumber", ns))
{
string quoteNumber = null;
string orderNumber = null;
using (var inner = xmlReader.ReadSubtree())
{
// We need to skip the insignificant whitespace around the CDATA nodes which ReadElementContentAsString() will not do.
while (inner.Read())
{
switch (xmlReader.NodeType)
{
case XmlNodeType.Text:
case XmlNodeType.CDATA:
quoteNumber += inner.Value;
break;
}
}
// After ReadSubtree() the reader is positioned on the </quoteNumber> element end.
}
// If the next orderNumber node is nmissing, ReadToFollowing() will read all the way past the next quoteNumber node.
// Use ReadToNextSibling() instead.
if (xmlReader.ReadToNextSibling("orderNumber", ns))
{
using (var inner = xmlReader.ReadSubtree())
{
while (inner.Read())
{
switch (xmlReader.NodeType)
{
case XmlNodeType.Text:
case XmlNodeType.CDATA:
orderNumber += inner.Value;
break;
}
}
}
}
if (quoteNumber != null && orderNumber != null)
list.Add(Tuple.Create(quoteNumber, orderNumber));
else
{
// Add error handling here
}
}
Notes:
CDATA is just an alternate way of encoding an XML character data node, see What does <![CDATA[]]> in XML mean? for details. XmlReader.Value will contain the unescaped value of an XML character data node regardless of whether it is encoded as a regular text node or a CDATA node.
It is unclear from your question whether there must be exactly one <quoteNumber> node in the XML file. Because of that I read the quote and order number pairs into a List<Tuple<string, string>>. After reading is complete you can check how many were read and add then to Globals.COData as appropriate.
XmlReader.ReadToFollowing() returns
true if a matching element is found; otherwise false and the XmlReader is in an end of file state.
Thus its return value needs to be check to make sure you don't try to read past the end of the file.
Your code doesn't attempt to handle situations where an <orderNumber> is missing. If it is, the code will may skip all the way past the next <quoteNumber> to read its order number. To avoid this possibility I use XmlReader.ReadToNextSibling() to limit the scope of the search to <orderNumber> nodes belonging to the same parent node.
By using XmlReader.ReadToFollowing("orderNumber") you hardcode your code to assume that the orderNumber node(s) have no namespace prefix. Rather than doing that, it would be safer to explicitly indicate the namespace they are in which seems to be something like http://intelliquip.com/integrationS... where the ... portion is not shown.
I recommend using XmlReader.ReadToFollowing("orderNumber", ns) where ns is the namespace the order and quote nodes are actually in.
XmlTextReader has been deprecated since .Net 2.0. Use XmlReader.Create() instead.
The XmlReader API is rather fussy to use. If your XML files are not large you might consider loading them into an XDocument and using LINQ to XML to query it.
For instance, your XmlReader code could be rewritten as follows:
var doc = XDocument.Load(FilePath);
XNamespace ns = ""; // Replace with #"http://intelliquip.com/integrationS..." can't see the full namespace from the XML image.
var query = from quote in doc.Descendants(ns + "quoteNumber")
let order = quote.ElementsAfterSelf(ns + "orderNumber").FirstOrDefault()
where order != null
select Tuple.Create(quote.Value, order.Value);
var list = query.ToList();
Which looks much simpler.
You might also consider replacing the Tuple<string, string> with a proper data model such as
public class Order
{
public string QuoteNumber { get; set; }
public string OrderNumber { get; set; }
}
Demo fiddle #1 here for XmlReader and #2 here for LINQ to XML.

Reading a Text File that has XML data C# [duplicate]

How do I read and parse an XML file in C#?
XmlDocument to read an XML from string or from file.
using System.Xml;
XmlDocument doc = new XmlDocument();
doc.Load("c:\\temp.xml");
or
doc.LoadXml("<xml>something</xml>");
then find a node below it ie like this
XmlNode node = doc.DocumentElement.SelectSingleNode("/book/title");
or
foreach(XmlNode node in doc.DocumentElement.ChildNodes){
string text = node.InnerText; //or loop through its children as well
}
then read the text inside that node like this
string text = node.InnerText;
or read an attribute
string attr = node.Attributes["theattributename"]?.InnerText
Always check for null on Attributes["something"] since it will be null if the attribute does not exist.
LINQ to XML Example:
// Loading from a file, you can also load from a stream
var xml = XDocument.Load(#"C:\contacts.xml");
// Query the data and write out a subset of contacts
var query = from c in xml.Root.Descendants("contact")
where (int)c.Attribute("id") < 4
select c.Element("firstName").Value + " " +
c.Element("lastName").Value;
foreach (string name in query)
{
Console.WriteLine("Contact's Full Name: {0}", name);
}
Reference: LINQ to XML at MSDN
Here's an application I wrote for reading xml sitemaps:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Data;
using System.Xml;
namespace SiteMapReader
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Please Enter the Location of the file");
// get the location we want to get the sitemaps from
string dirLoc = Console.ReadLine();
// get all the sitemaps
string[] sitemaps = Directory.GetFiles(dirLoc);
StreamWriter sw = new StreamWriter(Application.StartupPath + #"\locs.txt", true);
// loop through each file
foreach (string sitemap in sitemaps)
{
try
{
// new xdoc instance
XmlDocument xDoc = new XmlDocument();
//load up the xml from the location
xDoc.Load(sitemap);
// cycle through each child noed
foreach (XmlNode node in xDoc.DocumentElement.ChildNodes)
{
// first node is the url ... have to go to nexted loc node
foreach (XmlNode locNode in node)
{
// thereare a couple child nodes here so only take data from node named loc
if (locNode.Name == "loc")
{
// get the content of the loc node
string loc = locNode.InnerText;
// write it to the console so you can see its working
Console.WriteLine(loc + Environment.NewLine);
// write it to the file
sw.Write(loc + Environment.NewLine);
}
}
}
}
catch { }
}
Console.WriteLine("All Done :-)");
Console.ReadLine();
}
static void readSitemap()
{
}
}
}
Code on Paste Bin
http://pastebin.com/yK7cSNeY
There are lots of way, some:
XmlSerializer. use a class with the target schema
you want to read - use XmlSerializer
to get the data in an Xml loaded into
an instance of the class.
Linq 2 xml
XmlTextReader.
XmlDocument
XPathDocument (read-only access)
You could use a DataSet to read XML strings.
var xmlString = File.ReadAllText(FILE_PATH);
var stringReader = new StringReader(xmlString);
var dsSet = new DataSet();
dsSet.ReadXml(stringReader);
Posting this for the sake of information.
You can either:
Use XmlSerializer class
Use XmlDocument class
Examples are on the msdn pages provided
Linq to XML.
Also, VB.NET has much better xml parsing support via the compiler than C#. If you have the option and the desire, check it out.
Check out XmlTextReader class for instance.
There are different ways, depending on where you want to get.
XmlDocument is lighter than XDocument, but if you wish to verify minimalistically that a string contains XML, then regular expression is possibly the fastest and lightest choice you can make. For example, I have implemented Smoke Tests with SpecFlow for my API and I wish to test if one of the results in any valid XML - then I would use a regular expression. But if I need to extract values from this XML, then I would parse it with XDocument to do it faster and with less code. Or I would use XmlDocument if I have to work with a big XML (and sometimes I work with XML's that are around 1M lines, even more); then I could even read it line by line. Why? Try opening more than 800MB in private bytes in Visual Studio; even on production you should not have objects bigger than 2GB. You can with a twerk, but you should not. If you would have to parse a document, which contains A LOT of lines, then this documents would probably be CSV.
I have written this comment, because I see a lof of examples with XDocument. XDocument is not good for big documents, or when you only want to verify if there the content is XML valid. If you wish to check if the XML itself makes sense, then you need Schema.
I also downvoted the suggested answer, because I believe it needs the above information inside itself. Imagine I need to verify if 200M of XML, 10 times an hour, is valid XML. XDocument will waste a lof of resources.
prasanna venkatesh also states you could try filling the string to a dataset, it will indicate valid XML as well.
public void ReadXmlFile()
{
string path = HttpContext.Current.Server.MapPath("~/App_Data"); // Finds the location of App_Data on server.
XmlTextReader reader = new XmlTextReader(System.IO.Path.Combine(path, "XMLFile7.xml")); //Combines the location of App_Data and the file name
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
break;
case XmlNodeType.Text:
columnNames.Add(reader.Value);
break;
case XmlNodeType.EndElement:
break;
}
}
}
You can avoid the first statement and just specify the path name in constructor of XmlTextReader.
If you want to retrive a particular value from an XML file
XmlDocument _LocalInfo_Xml = new XmlDocument();
_LocalInfo_Xml.Load(fileName);
XmlElement _XmlElement;
_XmlElement = _LocalInfo_Xml.GetElementsByTagName("UserId")[0] as XmlElement;
string Value = _XmlElement.InnerText;
Here is another approach using Cinchoo ETL - an open source library to parse xml file with few lines of code.
using (var r = ChoXmlReader<Item>.LoadText(xml)
.WithXPath("//item")
)
{
foreach (var rec in r)
rec.Print();
}
public class Item
{
public string Name { get; set; }
public string ProtectionLevel { get; set; }
public string Description { get; set; }
}
Sample fiddle: https://dotnetfiddle.net/otYq5j
Disclaimer: I'm author of this library.

Parsing XML from string

I'm sure this is very simple..
I have this as a string:
<OnTheRoadQuote xmlns:i="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://schemas.datacontract.org/2004/07/OTRAPI.Services.Models">
<BasicPrice>15595.8333</BasicPrice>
<CO2>93</CO2>
<Dealer>Audi</Dealer>
<DeliveryCost>524.9900</DeliveryCost>
<DiscountPrice>14348.166636</DiscountPrice>
<DiscountSum>1247.666664</DiscountSum>
<Discounts>
<Discount>
<DiscountApplication>Percentage</DiscountApplication>
<DiscountDescription>Dealer Discount on Vehicle and Options %</DiscountDescription>
<DiscountID>Discount1</DiscountID>
<DiscountType>VehicleAndOptions</DiscountType>
<DiscountValue>8</DiscountValue>
</Discount>
</Discounts>
<OTR>17902.7879632</OTR>
</OnTheRoadQuote>
How do I read the value of the OTR node?
I've got an XmlReader but not sure how to use it.
Thanks
Using XmlReader, and fixing a typo in your root element (missing space before the second xmlns):
string xml = #"<OnTheRoadQuote xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"" xmlns=""http://schemas.datacontract.org/2004/07/OTRAPI.Services.Models"">
<BasicPrice>15595.8333</BasicPrice>
<CO2>93</CO2>
<Dealer>Audi</Dealer>
<DeliveryCost>524.9900</DeliveryCost>
<DiscountPrice>14348.166636</DiscountPrice>
<DiscountSum>1247.666664</DiscountSum>
<Discounts>
<Discount>
<DiscountApplication>Percentage</DiscountApplication>
<DiscountDescription>Dealer Discount on Vehicle and Options %</DiscountDescription>
<DiscountID>Discount1</DiscountID>
<DiscountType>VehicleAndOptions</DiscountType>
<DiscountValue>8</DiscountValue>
</Discount>
</Discounts>
<OTR>17902.7879632</OTR>
</OnTheRoadQuote>";
string otrValue = "";
using (XmlReader reader = XmlReader.Create(new StringReader(xml))) // use a StringReader to load the XML string into an XmlReader
{
reader.ReadToFollowing("OTR"); // move the reader to OTR
reader.ReadStartElement(); // consume the start element
otrValue = reader.Value; // store the value in the otrValue string.
}
Keep in mind that XmlReader is forward only, meaning that you can't navigate it backwards through the XML data to read, for example, Discounts, once you've pushed it to the OTR node. If you want to do that, you should look into using XmlDocument or (preferably) XDocument. However, if all you need to do is get the OTR value, this should be the most efficient (time and space) way of doing so.
With less code, you can use LINQ to XML and load an XElement with the xml or a file. There are also other options.
XElement element = XElement.Load(....);
var node = element.Element("OTR");
https://msdn.microsoft.com/en-us/library/system.xml.linq.xelement.load%28v=vs.110%29.aspx

How to append new item into serialized xml data without deserialize old data?

Normally, I use the following code to serialize object to XML file. Everyday, I have about 100-1000 new items to be added into this list in different period of time.
var xmlSerializer = new XmlSerializer(typeof(List<TestModel>));
xmlSerializer.Serialize(stream, list);
How to append new item into serialized xml data without deserialize old data?
Thanks,
You can serialize objecto to memory and append to existing file. Also take a look at MS article Efficient Techniques for Modifying Large XML Files which shows two techniques both applicable in your situation.
There is no way of doing what you want using only the XmlSerializer that I can think of, but with a little bit of extra work this is possible.
A simple approach to this would be to serialize the list for the first item(s) of the day - as your existing code does. When new data comes in, you can now open the saved xml using an XmlDocument and append the serialization of one single item at a time.
One thing to note is that if the resulting xml is extremely big, the XmlDocument may grow very large (and may be slow or even cause OutOfMemoryExceptions as Pavel Kyments notes in a comment), in this case you may want to investigate XmlReader and XmlWriter to append the xml serially. However the overall approach would remain the same (open->serialize your new item->append the generated xml->resave)
[EDIT - changed code sample to show chained XmlReader/XmlWriter, rather than XmlDocument approach]
Something along these lines:
public static void AppendToXml(
Stream xmlSource, // your existing xml - could be from a file, etc
Stream updatedXmlDestination, // your target xml, could be a different file
string rootElementName, // the root element name of your list, e.g. TestModels
TestModel itemToAppend) // the item to append
{
var writerSettings = new XmlWriterSettings {Indent = true, IndentChars = " " };
using (var reader = XmlReader.Create(xmlSource))
using (var writer = XmlWriter.Create(updatedXmlDestination, writerSettings))
{
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.XmlDeclaration:
break;
case XmlNodeType.Element:
writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
if (reader.HasAttributes)
{
while (reader.MoveToNextAttribute())
{
writer.WriteAttributeString(reader.Prefix, reader.LocalName, reader.NamespaceURI, reader.Value);
}
}
if (reader.IsEmptyElement)
writer.WriteEndElement();
break;
case XmlNodeType.EndElement:
if (reader.Name == rootElementName)
{
var serializer = new XmlSerializer(typeof(TestModel));
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
serializer.Serialize(writer, itemToAppend, ns);
}
writer.WriteEndElement();
break;
case XmlNodeType.Text:
writer.WriteRaw(SecurityElement.Escape(reader.Value));
break;
case XmlNodeType.CDATA:
writer.WriteCData(reader.Value);
break;
}
}
}
}
Note: you may want to add support for other node types (omitted here for brevity), such as Whitespace, Comments, Processing Instructions, etc. These all follow the same pattern as CDATA above: put a case in, call the appropriate writer method.
With this updated approach - you never have more than a small amount in memory at any given time.
I don't think it is possible. You want to perform random access to a block of data that is serialized and deserialized, so it has to be accessed sequentially.
Maybe you can modify directly the XML document, which will be faster, but you'll be losing the facilities of using a serialized/deserialized object tree, which is much more easy to manipulate (add/remove objects, ...)

How do I read and parse an XML file in C#?

How do I read and parse an XML file in C#?
XmlDocument to read an XML from string or from file.
using System.Xml;
XmlDocument doc = new XmlDocument();
doc.Load("c:\\temp.xml");
or
doc.LoadXml("<xml>something</xml>");
then find a node below it ie like this
XmlNode node = doc.DocumentElement.SelectSingleNode("/book/title");
or
foreach(XmlNode node in doc.DocumentElement.ChildNodes){
string text = node.InnerText; //or loop through its children as well
}
then read the text inside that node like this
string text = node.InnerText;
or read an attribute
string attr = node.Attributes["theattributename"]?.InnerText
Always check for null on Attributes["something"] since it will be null if the attribute does not exist.
LINQ to XML Example:
// Loading from a file, you can also load from a stream
var xml = XDocument.Load(#"C:\contacts.xml");
// Query the data and write out a subset of contacts
var query = from c in xml.Root.Descendants("contact")
where (int)c.Attribute("id") < 4
select c.Element("firstName").Value + " " +
c.Element("lastName").Value;
foreach (string name in query)
{
Console.WriteLine("Contact's Full Name: {0}", name);
}
Reference: LINQ to XML at MSDN
Here's an application I wrote for reading xml sitemaps:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Data;
using System.Xml;
namespace SiteMapReader
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Please Enter the Location of the file");
// get the location we want to get the sitemaps from
string dirLoc = Console.ReadLine();
// get all the sitemaps
string[] sitemaps = Directory.GetFiles(dirLoc);
StreamWriter sw = new StreamWriter(Application.StartupPath + #"\locs.txt", true);
// loop through each file
foreach (string sitemap in sitemaps)
{
try
{
// new xdoc instance
XmlDocument xDoc = new XmlDocument();
//load up the xml from the location
xDoc.Load(sitemap);
// cycle through each child noed
foreach (XmlNode node in xDoc.DocumentElement.ChildNodes)
{
// first node is the url ... have to go to nexted loc node
foreach (XmlNode locNode in node)
{
// thereare a couple child nodes here so only take data from node named loc
if (locNode.Name == "loc")
{
// get the content of the loc node
string loc = locNode.InnerText;
// write it to the console so you can see its working
Console.WriteLine(loc + Environment.NewLine);
// write it to the file
sw.Write(loc + Environment.NewLine);
}
}
}
}
catch { }
}
Console.WriteLine("All Done :-)");
Console.ReadLine();
}
static void readSitemap()
{
}
}
}
Code on Paste Bin
http://pastebin.com/yK7cSNeY
There are lots of way, some:
XmlSerializer. use a class with the target schema
you want to read - use XmlSerializer
to get the data in an Xml loaded into
an instance of the class.
Linq 2 xml
XmlTextReader.
XmlDocument
XPathDocument (read-only access)
You could use a DataSet to read XML strings.
var xmlString = File.ReadAllText(FILE_PATH);
var stringReader = new StringReader(xmlString);
var dsSet = new DataSet();
dsSet.ReadXml(stringReader);
Posting this for the sake of information.
You can either:
Use XmlSerializer class
Use XmlDocument class
Examples are on the msdn pages provided
Linq to XML.
Also, VB.NET has much better xml parsing support via the compiler than C#. If you have the option and the desire, check it out.
Check out XmlTextReader class for instance.
There are different ways, depending on where you want to get.
XmlDocument is lighter than XDocument, but if you wish to verify minimalistically that a string contains XML, then regular expression is possibly the fastest and lightest choice you can make. For example, I have implemented Smoke Tests with SpecFlow for my API and I wish to test if one of the results in any valid XML - then I would use a regular expression. But if I need to extract values from this XML, then I would parse it with XDocument to do it faster and with less code. Or I would use XmlDocument if I have to work with a big XML (and sometimes I work with XML's that are around 1M lines, even more); then I could even read it line by line. Why? Try opening more than 800MB in private bytes in Visual Studio; even on production you should not have objects bigger than 2GB. You can with a twerk, but you should not. If you would have to parse a document, which contains A LOT of lines, then this documents would probably be CSV.
I have written this comment, because I see a lof of examples with XDocument. XDocument is not good for big documents, or when you only want to verify if there the content is XML valid. If you wish to check if the XML itself makes sense, then you need Schema.
I also downvoted the suggested answer, because I believe it needs the above information inside itself. Imagine I need to verify if 200M of XML, 10 times an hour, is valid XML. XDocument will waste a lof of resources.
prasanna venkatesh also states you could try filling the string to a dataset, it will indicate valid XML as well.
public void ReadXmlFile()
{
string path = HttpContext.Current.Server.MapPath("~/App_Data"); // Finds the location of App_Data on server.
XmlTextReader reader = new XmlTextReader(System.IO.Path.Combine(path, "XMLFile7.xml")); //Combines the location of App_Data and the file name
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
break;
case XmlNodeType.Text:
columnNames.Add(reader.Value);
break;
case XmlNodeType.EndElement:
break;
}
}
}
You can avoid the first statement and just specify the path name in constructor of XmlTextReader.
If you want to retrive a particular value from an XML file
XmlDocument _LocalInfo_Xml = new XmlDocument();
_LocalInfo_Xml.Load(fileName);
XmlElement _XmlElement;
_XmlElement = _LocalInfo_Xml.GetElementsByTagName("UserId")[0] as XmlElement;
string Value = _XmlElement.InnerText;
Here is another approach using Cinchoo ETL - an open source library to parse xml file with few lines of code.
using (var r = ChoXmlReader<Item>.LoadText(xml)
.WithXPath("//item")
)
{
foreach (var rec in r)
rec.Print();
}
public class Item
{
public string Name { get; set; }
public string ProtectionLevel { get; set; }
public string Description { get; set; }
}
Sample fiddle: https://dotnetfiddle.net/otYq5j
Disclaimer: I'm author of this library.

Categories

Resources