Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LINQ to XML - Get given XElement's text content without child elements' text content

Tags:

linq-to-xml

I have just started using LINQ to XML, and I am having trouble getting the text contents of a given XElement without getting the text contents of all the child elements as well.

So for example, if I have the following XML document:

<?xml version="1.0" encoding="utf-8" ?>
<root xmlns="example.org/rootns">This is root value
    <children>
        <child name='child 1'>value 1</child>
        <child name='child 2'>value 2
            <grandchild name='grandchild A'>value A</grandchild>
        </child>
    </children>
</root>

And I use the following Test method:

private static void Test()
{
    string xString = @"<?xml version=""1.0"" encoding=""utf-8"" ?><root xmlns=""example.org/rootns"">This is root value<children><child name='child 1'>value 1</child><child name='child 2'>value 2<grandchild name='grandchild A'>value A</grandchild></child></children></root>";

    var xDoc = XDocument.Parse(xString);

    XNamespace ns = @"example.org/rootns";
    string elemName = "child";

    var xElems = from e in xDoc.Descendants(ns + elemName)
                 select e;

    foreach (var xElem in xElems)
    {
        Console.WriteLine(xElem.Value);
    }
}

Then I get two lines on output:

    value 1
    value 2value A

The first line shows the content of the first child - this is okay. The second line however shows not only the text content of the first child, but also any decendants of that child.

How can I get the text content of just the second child without the grandchild's text content as well?

Also note that the sample is just a simple example to illustrate what I am doing, and in production I will not necessarily know what the child elements are called (if any), but I should be able to get the element I need to get the text content from.


Jon Skeet's answer helped with the solution. Just replace the foreach loop with the following to select text XNodes rather than the XElement's value:

...
foreach (var xElem in xElems)
{
    var values = from n in xElem.Nodes()
                 where n.NodeType == System.Xml.XmlNodeType.Text
                 select n;

    if (values != null && values.Count() > 0)
        Console.WriteLine(values.First());
}
like image 294
Avery Avatar asked Apr 24 '12 16:04

Avery


1 Answers

What do you want to do if there are multiple text nodes? For example, you could join them all together:

var text = string.Join("", element.Nodes.OfType<XText>().Select(x => x.Value));

EDIT: If you only want a single element, it's easier than you've shown:

var textNode = xElem.Nodes().OfType<XText>().FirstOrDefault();
if (textNode != null)
{
    Console.WriteLine(textNode.Value);
}
like image 83
Jon Skeet Avatar answered Sep 22 '22 13:09

Jon Skeet