Retrieve full string of XElement with mixed content
Asked Answered
F

6

7

Let's say I have the following content in an XElement object

<root>Hello<child>Wold</child></root>

If I use XElement.ToString(), this gives me

"<root xmnls="someschemauri">Hello<child>World</child></root>"

If I use XElement.Value, I will get

"Hello World"

I need to get

"Hello <child>World</child>"

What is the proper function to do this(if there is one)?

Fernald answered 7/3, 2013 at 19:53 Comment(1)
Which version of .NET are you using? The answers are different for .NET 4.0 and above.Tita
W
6

Solution for .NET 4

var result = String.Join("", rootElement.Nodes()).Trim();

Complete code (for .NET 3.5):

XElement rootElement = XElement.Parse("<root>Hello<child>Wold</child></root>");
var nodes = rootElement.Nodes().Select(n => n.ToString()).ToArray();
string result = String.Join("", nodes).Trim();
Console.WriteLine(result);
// writes "Hello<child>World</child>"

Fast solution without joining all nodes:

XElement rootElement = XElement.Parse("<root>Hello<child>Wold</child></root>");
var reader = rootElement.CreateReader();
reader.MoveToContent();
string result = reader.ReadInnerXml(); 
Wolfhound answered 7/3, 2013 at 20:22 Comment(8)
@Magnum you are doing something wrong. There should not bee root node itself. Only nodes are joined.Wolfhound
I got the rootElement is derived from XDocument.Root property., so I simply did String.Join("", xDoc.Root.Nodes()).Trim(); and the aforementioned output is what I got.Colley
@Colley then your <root> element is not Root of document. Select your <root> element insteadWolfhound
xElement.Nodes() does not return a string array, I can't use it in the String.Join function. I'm on .NET 3.5 btwFernald
@Fernald on .NET 4 String.Join works with IEnumerable. Btw call .ToArray() on .NET 3.5Wolfhound
this will do, I tough there was something easier than running a linq query thought.Fernald
@Fernald I've added nice solution with simple XmlReader which you can create from element.Wolfhound
That's nice, what's the better solution regarding performance. This will get called quite often.Fernald
C
1

This worked rather nicely:

//SOLUTION BY Nenad
var element = XElement.Parse("<root>Hello<child>World</child></root>");
string xml = string.Join("", element.DescendantNodes().Select(e => e.ToString()));
Debug.WriteLine(xml);

Final output: Hello<child>Wold</child>World


Try #3

XDocument xDoc = XDocument.Parse(@"<root>Hello<child>World</child></root>");
XElement rootElement = xDoc.Root;
Debug.WriteLine(rootElement.Value + rootElement.FirstNode.ToString());
Colley answered 7/3, 2013 at 19:58 Comment(8)
Or maybe .Nodes.ToString()?Tita
@JohnSaunders I thought about that but his example is very simplistic so the nodes would return child nodes and not necessarily comments or otherwise no? Since I don't know what his eventual xml file will look like, I used Descendants.Colley
nah that's not it, it Nodes() and Descendant() gives me some weird stuff like System.Xml.Linq.XContainer+d__a System.Xml.Linq.XContainer+d__a instead of a tag and value System.Xml.Linq.XContainFernald
But, does Descendants return text?Tita
No it does not, it returns a collection of XElement obviously.Fernald
@Fernald Sorry, I'm about to update my answer, working on a full solution in a new solution I created.Colley
Magnum, your answer would work in this specific example context but currently I dont have access to the XDocument object where I'm in my code. I must come up with something from the XElementFernald
Put element.Nodes(), only direct children. "World" was duplicated at the end as it's deeper nested XText node. :)Curtal
C
1

This will do:

var element = XElement.Parse("<root>Hello<child>Wold</child></root>");
string xml = string.Join("", element.Nodes().Select(e => e.ToString()));

For .NET 3.5 (if that was the point of question):

var element = XElement.Parse("<root>Hello<child>Wold</child></root>");
string xml = string.Join("", element.Nodes().Select(e => e.ToString()).ToArray());
Curtal answered 7/3, 2013 at 20:33 Comment(6)
This returns "Hello<child>Wold</child>Wold", with unnecessary Wold and the end.Annotate
Fixed - Nodes(), not DescendandNodes().Curtal
Same question - how it differs from my answer?Wolfhound
Your first/main line is little bit akward. Why Trim? And doesn't work in .NET 3.5. You fixed it later too.Curtal
@Curtal first line was written before OP mentioned about 3.5 (see timeline). That's why code below fixed. Trim is needed for non-single line xml. Otherwise you will get empty lines at start and at end.Wolfhound
1st - your answer was confusing (way you wrote it), 2nd - that Trim() would fix start and end of the string, but all child nodes would still have their white spaces, so what's the point?Curtal
N
1

Extension method based on fastest know solution:

public static class XElementExtension
{
    public static string InnerXML(this XElement el) {
        var reader = el.CreateReader();
        reader.MoveToContent();
        return reader.ReadInnerXml();
    }
}

Then simple call it: xml.InnerXML();

Neon answered 18/12, 2015 at 20:32 Comment(0)
T
0

I don't have time to test this, but try:

var inners = from n in xelementVariableName.Nodes()
                       select n;
return String.Join(String,Empty, inners);

Tested:

public static string ReturnInnerXml()
{
    var doc = XDocument.Parse(@"<root>Hello<child>World</child></root>");
    var root = doc.Root;
    if (root == null)
    {
        throw new InvalidOperationException("No root");
    }

    var inners = from n in root.Nodes()
                 select n;
    return String.Join(String.Empty, inners);
}

This produces:

Hello<child>World</child>

Using .NET 4.0.

Tita answered 7/3, 2013 at 20:9 Comment(1)
By that I assume you mean this : var inners = from element in xElement.Nodes() select element.ToString();return inners.Aggregate((content, next) => next + " " + content); and sadly it returns the root tag includedFernald
A
0

Here it is:

var element = XElement.Parse("<root>Hello<child>Wold</child></root>");
string xml = string.Join("", element.Nodes().Select(e => e.ToString()).ToArray());

Returns Hello<child>Wold</child> and works on .NET 3.5

Annotate answered 7/3, 2013 at 20:47 Comment(1)
How it differs from my answer?Wolfhound

© 2022 - 2024 — McMap. All rights reserved.