Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get XElement's value and not value of all child-nodes?

Tags:

c#

xelement

Sample xml:

<parent>
<child>test1</child>
<child>test2</child>
</parent>

If I look for parent.Value where parent is XElement, I get "test1test2". What I am expecting is "". (since there is no text/value for .

What property of XElement should I be looking for?

like image 261
NiTiN Avatar asked Nov 22 '10 23:11

NiTiN


4 Answers

When looking for text data in the <parent> element you should look for child nodes that have NodeType properties equal to XmlNodeType.Text. These nodes will be of type XText. The following sample illustrates this:

var p = XElement
    .Parse("<parent>Hello<child>test1</child>World<child>test2</child>!</parent>");

var textNodes = from c in p.Nodes()
                where c.NodeType == XmlNodeType.Text
                select (XText)c;

foreach (var t in textNodes)
{
    Console.WriteLine(t.Value);
}

Update: if all you want is the first Text node, if any, here's an example using LINQ method calls instead of query comprehension syntax:

var firstTextNode = p.Nodes().OfType<XText>().FirstOrDefault();
if (firstTextNode != null)
{
    var textValue = firstTextNode.Value;
    ...do something interesting with the value
}

Note: using First() or FirstOrDefault() will be more performant than Count() > 0 in this scenario. Count always enumerates the whole collection while FirstOrDefault() will only enumerate until a match is found.

like image 95
Peter Lillevold Avatar answered Nov 12 '22 05:11

Peter Lillevold


You could concatenate the value of all XText nodes in parent:

XElement parent = XElement.Parse(
    @"<parent>Hello<child>test1</child>World<child>test2</child>!</parent>");

string result = string.Concat(
    parent.Nodes().OfType<XText>().Select(t => t.Value));

// result  ==  "HelloWorld!"

For comparison:

// parent.Value  ==  "Hellotest1Worldtest2!"

// (parent.HasElements ? "" : parent.Value)  ==  ""
like image 43
dtb Avatar answered Nov 12 '22 05:11

dtb


It is amazing that a coder somewhere at Microsoft thought that returning all text values as a concatenated and undelimited string would be useful. Luckily, another MS developer wrote an XElement extension to return what they call the "Shallow Value" of the text node here. For those who get the willies from clicking on links, the function is below...

    public static string ShallowValue(this XElement element)
    {
        return element
               .Nodes()
               .OfType<XText>()
               .Aggregate(new StringBuilder(),
                          (s, c) => s.Append(c),
                          s => s.ToString());
    }

And you call it like this, because it gives you all the whitespace too (or, come to think of it, you could trim it in the extension, whatever)

// element is a var in your code of type XElement ...
string myTextContent = element.ShallowValue().Trim();
like image 8
Steve Hibbert Avatar answered Nov 12 '22 05:11

Steve Hibbert


msdn says:

A String that contains all of the text content of this element. If there are multiple text nodes, they will be concatenated.

So the behaviour is to be expected.

You could solve your problem by doing:

string textContent = parent.HasElements ? "" : parent.Value;
like image 1
Femaref Avatar answered Nov 12 '22 05:11

Femaref