2
<bookstore>
  <book>
    <bookID>100</bookID>
    <name> The cat in the hat </name>
  </book>
  <book>
    <bookID>90</bookID>
    <name> another book </name>
  </book>
  <book>
    <bookID>103</bookID>
    <name> a new book </name>
  </book>
</bookstore>

I'm trying to sellect the bookID value from a XML document.The method I currently use is Element(bookID).Value But sometimes the bookID comes as an attribute of book like this: <book bookID=100> Is there a way of doing that in c#, like a xPath expression maybe? Many thanks!

3
  • You should make sure your XML structure is fixed by a schema before you start dealing with it. It will save you from a lot of trouble later. Commented Aug 5, 2015 at 5:44
  • 2
    what's the problem with solution suggested in the previous question? Commented Aug 5, 2015 at 5:48
  • @har07 I am googling let key word and trying to understand that solution. That's why I haven't responded yet. I am quite new to C#. Apologies.. Commented Aug 5, 2015 at 8:01

2 Answers 2

2

In XPath, you can use union (|) operator to combine query that return different part of the XML. For example :

//book/bookID/text() | //book/@bookID

The above XPath returns text content of bookID element and bookID attribute in document order. See the demo which using XmlDocument.SelectNodes() to execute the XPath.

Demo Codes :

var xml = @"<bookstore>
  <book>
    <bookID>100</bookID>
    <name> The cat in the hat </name>
  </book>
  <book bookID='90'>
    <name> a new book </name>
  </book>
  <book>
    <bookID>103</bookID>
    <name> another book </name>
  </book>
</bookstore>";
var doc = new XmlDocument();
doc.LoadXml(xml);
var result = doc.SelectNodes("//book/bookID/text() | //book/@bookID");
foreach (XmlNode r in result)
{
    Console.WriteLine(r.Value);
}

output :

100
90
103
Sign up to request clarification or add additional context in comments.

Comments

2

Does this need to be an XPath expression or can you use Linq with the XDocument system.

For example.

var xDocument = XDocument.Parse(@"<bookstore>
                                <book>
                                <bookID>100</bookID>
                                <name> The cat in the hat </name>
                                </book>
                                <book bookID=""90"">
                                <name> another book </name>
                                </book>
                                <book>
                                <bookID>103</bookID>
                                <name> a new book </name>
                                </book>
                                </bookstore>");

foreach (var xBook in xDocument.Descendants("book"))
{
    var bookIdNode = xBook.Elements("bookID").FirstOrDefault();
    int bookId = 0;

    ///there is a book id as an element
    if (bookIdNode != null)
    {
        //invalid book id.. should be an int
        if (!int.TryParse(bookIdNode.Value, out bookId))
            continue;
    }
    else
    {
        var bookIdAttr = xBook.Attributes("bookID").FirstOrDefault();
        if (bookIdAttr == null || !int.TryParse(bookIdAttr.Value, out bookId))
            continue;
    }

    if (bookId == 0)
        continue;

    //else we got our book id

}

This code is quite simple, just enumerates over the descendants with the element name book. It first checks if there is an element named bookID (case sensitive). If there is it attempts to parse the book id out as an int using the method int.TryParse().

If there are no bookID elements it next checks if there are any attributes with the name bookID and grabs the first instance (or null) using FirstOrDefault() extension method. If there is an instance of the bookID attribute it also try to parse the int using the int.TryParse() method.

By the end of the small snippet we have then check if the bookId is 0 if it is zero we can assume something went wrong. However this shouldnt happen as the logic should keep enumerating and forget about Elements without a bookID element or bookID attribute.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.