简体   繁体   中英

C# XmlElement: SelectSingleNode returns null for empty string?

I'm new to C#, and just started using XmlElement and its SelectSingleNode method. In my XML file there's a tag that may have a value (ie <tag>value</tag> ) or be empty (ie <tag></tag> ). If it's empty, SelectSingleNode returns null.

I'm currently using the following code to catch the value of the tag:

XmlElement elem = ....
string s = elem.SelectSingleNode("somepath").Value;

This code obviously raises an exception for empty tags. However, for me an empty tag is a valid value, where I expect the value of my string to be "".

Wrapping each call to SelectSingleNode with try...catch seems a huge waste of code (I have many fields that may be empty), and I'm sure there's a better way to achieve this.

What is the recommended approach?

EDIT:

Following requests, a sample XML code will be:

<Elements>
    <Element>
        <Name>Value</Name>
        <Type>Value</Type> <-- may be empty
        <Color>Value</Color>
    </Element>
    <Element>
        <Name>Value</Name>
        <Type>Value</Type>
        <Color>Value</Color>
    </Element>
</Elements>

The CS code:

XmlDocument doc = new XmlDocument();
doc.Load("name.xml");

foreach (XmlElement elem in doc.SelectNodes("Elements/Element"))
{
    myvalue = elem.SelectSingleNode("Type/text()").Value;
}

Your sample code:

  myvalue = elem.SelectSingleNode("Type/text()").Value;

is where the problem is. The XPath expression you've used there doesn't mean "give me text of element Type ". It means "give me all child text nodes of element Type". And an empty element doesn't have any child text nodes (a text node cannot be empty in XPath document model). If you want to get text value of the node, you should use:

  myvalue = elem.SelectSingleNode("Type").InnerText;

The recommended approach would be to use .NET's new XML API (namely LINQ to XML).

Here is an example:

using System;
using System.Linq;
using System.Xml.Linq;

class Program
{
    static void Main()
    {
        String xml = @"<Root><Value></Value></Root>";

        var elements = XDocument.Parse(xml)
            .Descendants("Value")
            .Select(e => e.Value);
    }
}

http://msdn.microsoft.com/en-us/library/system.xml.xmlnode.value(VS.71).aspx

Because the "value" returned depends on the NodeType, there is a chance that the node will be interpreted as a type that can return NULL.

You might be better off using:

XmlElement elem = ....
string s = elem.SelectSingleNode("somepath").InnerText;

as XMLNode.InnerText (or XmlNode.InnerXML ) will return a string, including an empty string.

也许这对你有用:

string s = elem.SelectSingleNode("somepath") != null ? elem.SelectSingleNode("somepath").value : ""

When I'm actually bothering with XML DOM, you could write a helper method along the lines of:

static string NodeValue(XmlNode node, string defaultValue)
{
    if (node != null)
        return node.Value ?? defaultValue;

    return defaultValue;
}

Then you can do the following if you're not sure your node will exist:

string s = NodeValue(elem.SelectSingleNode("Type"), String.Empty);

If keeps your code readable, especially if you're doing this for multiple elements.

All that being said, SelectSingleNode(..) does not return a null value if the tag is empty. The Value attribute will be null however. If you're just trying to work around that, this should do:

string s = elem.SelectSingleNode("Type").Value ?? String.Empty;

Edit: ah, you're using /text() to select the actual text node. You could just get rid of that part of the XPath, but the NodeValue method I supplied should still work (the "?? defaultValue" part is not needed in that case though).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM