23

I'm planning to use XML for database purpose. Only thing I was able to do is read whole XML file. I want to be able to read only some data and I don't know how to do that.

Here is a simple XML

<Books>
 <Book>
  <Title>Animals</Title>
  <Author>J. Anderson</Author>
 </Book>
 <Book>
  <Title>Car</Title>
  <Author>L. Sawer</Author>
 </Book>
</Books> 

I'm interested in app where output is gonna be

Books:
Animals
Cars

Authors:
J. Anderson
L. Sawer

I'm just want to learn how read specific data from XML not whole file.

[SOLVED] I have used Linq to XML

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Safiron
  • 883
  • 4
  • 11
  • 30
  • 5
    Is the file too big to be read completely? You *can* use `XmlReader` to read just bits, but it's a *lot* simpler to read the lot in via LINQ to XML and then just *select* the bits you want... – Jon Skeet Aug 19 '11 at 09:49
  • file is not too big about 5-10 KB – Safiron Aug 20 '11 at 09:52

4 Answers4

50

I don't think you can "legally" load only part of an XML file, since then it would be malformed (there would be a missing closing element somewhere).

Using LINQ-to-XML, you can do var doc = XDocument.Load("yourfilepath"). From there its just a matter of querying the data you want, say like this:

var authors = doc.Root.Elements().Select( x => x.Element("Author") );

HTH.

EDIT:

Okay, just to make this a better sample, try this (with @JWL_'s suggested improvement):

using System;
using System.Xml.Linq;

namespace ConsoleApplication1 {
    class Program {
        static void Main( string[] args )  {
            XDocument doc = XDocument.Load( "XMLFile1.xml" );
            var authors = doc.Descendants( "Author" );
            foreach ( var author in authors ) {
                Console.WriteLine( author.Value );
            }
            Console.ReadLine();
        }
    }
}

You will need to adjust the path in XDocument.Load() to point to your XML file, but the rest should work. Ask questions about which parts you don't understand.

M. A. Kishawy
  • 5,001
  • 11
  • 47
  • 72
Tieson T.
  • 20,774
  • 6
  • 77
  • 92
  • 1
    I think doc.Decendants("Author") is a better alternative. – JWL_ Aug 19 '11 at 10:13
  • @JWL_ Probably. To be honest, I just typed in the first thing that came to mind. Thanks for the input! :) – Tieson T. Aug 20 '11 at 01:07
  • I'm trying to use this code but I'm confused what to do next. When I use Console.WriteLine(authors); it shows some nonsense. I do not realy understand how it works. Can you put here more complete code ? Thanks – Safiron Aug 20 '11 at 11:25
  • Well, `authors` would be an `IEnumerable` collection of `XElement`s, so yeah, `Console.WriteLine()` would just give you the default `.ToString()` of the underlying `object`. – Tieson T. Aug 22 '11 at 06:05
  • 1
    I used var authors = doc.Root.Elements().Select(x => x.Element("Author")); foreach (var author in authors) { Console.WriteLine(author); } – Safiron Sep 01 '11 at 06:08
  • @Safiron Added full sample. See answer. – Tieson T. Sep 01 '11 at 16:38
  • How can I achieve the same in my question: http://stackoverflow.com/questions/24268245/how-to-extract-every-occurence-of-tags-in-an-xml-file – Si8 Jun 17 '14 at 16:25
  • What if I have a root `` and then a child ``? How do I get the child `` value? I tried this: `var statement = x1.Element("statement").Descendants("statement");` but that didn't work :/ – Si8 Jun 17 '14 at 16:33
12

as per @Jon Skeet 's comment, you should use a XmlReader only if your file is very big. Here's how to use it. Assuming you have a Book class

public class Book {
    public string Title {get; set;}
    public string Author {get; set;}
}

you can read the XML file line by line with a small memory footprint, like this:

public static class XmlHelper {
    public static IEnumerable<Book> StreamBooks(string uri) {
        using (XmlReader reader = XmlReader.Create(uri)) {
            string title = null;
            string author = null;

            reader.MoveToContent();
            while (reader.Read()) {
                if (reader.NodeType == XmlNodeType.Element
                    && reader.Name == "Book") {
                    while (reader.Read()) {
                        if (reader.NodeType == XmlNodeType.Element &&
                            reader.Name == "Title") {
                            title = reader.ReadString();
                            break;
                        }
                    }
                    while (reader.Read()) {
                        if (reader.NodeType == XmlNodeType.Element &&
                            reader.Name == "Author") {
                            author =reader.ReadString();
                            break;
                        }
                    }
                    yield return new Book() {Title = title, Author = author};
                }
            }       
        }
    }

Example of usage:

string uri = @"c:\test.xml"; // your big XML file

foreach (var book in XmlHelper.StreamBooks(uri)) {
    Console.WriteLine("Title, Author: {0}, {1}", book.Title, book.Author);  
}
M. A. Kishawy
  • 5,001
  • 11
  • 47
  • 72
Paolo Falabella
  • 24,914
  • 3
  • 72
  • 86
  • thanks a lot, this is exactly how I thought it could be done. My database is not big no more than 50 records – Safiron Aug 19 '11 at 12:39
  • well, then I would not really use this approach. As you can see it's a lot of code to do what Linq.Xml would do in 2 or 3 lines of code. Take a look at @Tieson T.'s answer for instance. – Paolo Falabella Aug 19 '11 at 15:05
  • yeah its a good way but Linq is better for my purpose – Safiron Sep 03 '11 at 19:26
3

Alternatively, you can use XPathNavigator:

XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
XPathNavigator navigator = doc.CreateNavigator();

string books = GetStringValues("Books: ", navigator, "//Book/Title");
string authors = GetStringValues("Authors: ", navigator, "//Book/Author");

..

/// <summary>
/// Gets the string values.
/// </summary>
/// <param name="description">The description.</param>
/// <param name="navigator">The navigator.</param>
/// <param name="xpath">The xpath.</param>
/// <returns></returns>
private static string GetStringValues(string description,
                                      XPathNavigator navigator, string xpath) {
    StringBuilder sb = new StringBuilder();
    sb.Append(description);
    XPathNodeIterator bookNodesIterator = navigator.Select(xpath);
    while (bookNodesIterator.MoveNext())
       sb.Append(string.Format("{0} ", bookNodesIterator.Current.Value));
    return sb.ToString();
}
M. A. Kishawy
  • 5,001
  • 11
  • 47
  • 72
Strillo
  • 2,952
  • 13
  • 15
  • Can you please see one of my [question](https://stackoverflow.com/questions/55430357/how-to-get-xml-web-service-response-in-c-sharp) regarding the xml response? – Moeez Mar 31 '19 at 05:25
1

Try GetElementsByTagName method of XMLDocument class to read specific data or LoadXml method to read all data to xml document.

Rais Alam
  • 6,970
  • 12
  • 53
  • 84
Upendra Chaudhari
  • 6,473
  • 5
  • 25
  • 42