0

I have an string parameter with xml content in it. Basically the string have an XML inside.

string S = funcThatReturnsXML (parameters);

S have the next text:

<?xml version="1.0" encoding="utf-8" ?> 
<tagA>

<tagB> 

<tagBB>
..
.
.
</tagBB>
.
.
</tagB>

<tagC> 
..
..
.

</tagC>

</tagA>

The funcThatReturnsXML (parameters) creates an XmlDocument object but the return it as a string, I cant change this function, to much stuff works with it.

Tried to create XmlDocument objetc but the SelectSingleNode return null.

 XmlDocument xmlDoc = new XmlDocument();
                    xmlDoc.LoadXml(S);
                    XmlNode root = xmlDoc.SelectSingleNode("tagB");

How can I delete from string S (not XML Object) specific node, for example <tagB>

EDIT: this is the XML I tested with:

 <?xml version="1.0" ?> 
- <Request xmlns:xsi="http://www.mysite.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <info xmlns="http://www.mysite.com">
  <RequestTR>54</RequestTR> 
  <time>2013-12-22</time> 
  </info>
- <Parameters xmlns="http://www.mysite.com">
  <id>3</id> 
  <name>2</name> 
  </Parameters>
  <title>Request</title> 
  </Request>
5
  • Is there a specific reason why you can't make a XmlDocument instance, call LoadXml(), and work on it? I'm asking because you wrote "not XML Object". Commented Dec 18, 2013 at 13:38
  • In the funcThatReturnsXML (parameters) it is creating an XML Object but returning it as a string xmlObject.InnerXml. I cant change this base function so I just want to fix the string I'm working on Commented Dec 18, 2013 at 13:42
  • 1
    I suggest you (re)build an XmlDocument from the string anyway. Commented Dec 18, 2013 at 13:49
  • tried it...the xmlDoc.SelectSingleNode("tagB"); return null Commented Dec 18, 2013 at 15:58
  • The xpath is wrong... try either xmlDoc.SelectSingleNode("/tagA/tagB") or xmlDoc.SelectSingleNode("//tagB") . Commented Dec 18, 2013 at 16:11

3 Answers 3

2

Try this:

string S = funcThatReturnsXML(parameters);
var doc = XDocument.Parse(S);
var nodeToRemove = doc.Descendants("tagB");
nodeToRemove.Remove();

That will remove all nodes named "tagB" from string S which contains xml.

UPDATE 1:

Sorry, i missed to include one more line:

S = doc.ToString();

My first code above removed "tagB" from doc but didnt save it back to S variable.

UPDATE 2:

I tested with following xml which contain attribute:

<tagA attribute="value">
    <tagB> 
        <tagBB>
        </tagBB>
    </tagB>
    <tagC></tagC>
</tagA>

and the output of Console.WriteLine(S):

<tagA attribute="value">
    <tagC></tagC>
</tagA>

UPDATE 3:

Given your updated xml format, I know why my previous code didn't work for you. That was because your xml have namespace (xmlns) declared. The solution is to use LocalName when searching for the node to be removed, that will search for node name while ignoring its namespace. The follwoing example shows how to remove all "info" node:

var doc = XDocument.Parse(S);
var nodeToRemove = doc.Descendants().Where(o => o.Name.LocalName == "info");
nodeToRemove.Remove();
S = doc.ToString();
Sign up to request clarification or add additional context in comments.

4 Comments

@Dima see my update. If you checked whether <tabB> removed from S, then yes it wasn't, but it will by adding S = doc.ToString(); at the end.
@Dima I tested with an xml containing attribute and the program still working. Let me know the xml you have if it still not working for you
It still not working, I added the XML to my question
@Dima updated my answer. Try it out, it works for me.
1

If you can determine the particular outer element to remove from the returned XML, you could use LINQ to XML:

var returnedXml = funcThatReturnsXML(parameters);
var xmlElementToRemove = funcThatReturnsOuterElement(returnedXml);
var xelement = XElement.Load("XmlDoc.txt");
xelement.Elements().Where(e => e.Name == xmlElementToRemove).Remove();

For example:

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

class Program
{
    static void Main(string[] args)
    {
        // pretend this is the funThatReturnsXML return value
        var returnedXml = "<tagB><tagBB></tagBB></tagB>";
        // get the outer XML element name
        var xmlElementToRemove = GetOuterXmlElement(returnedXml);
        // load XML from where ever
        var xelement = XElement.Load("XmlDoc.txt");
        // remove the outer element and all subsequent elements
        xelement.Elements().Where(e => e.Name == xmlElementToRemove).Remove();
    }

    static string GetOuterXmlElement(string xml)
    {
        var index = xml.IndexOf('>');
        return xml.Substring(1, index - 1);
    }
}

Note that the above is a "greedy" removal method, if there is more than once element with the name returned via the GetOuterXmlElemet method they will all be removed. If you want a specific instance to be removed then you will require something more sophisticated.

Comments

1

Building on your edit:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(S);

var nodeA = xmlDoc.SelectSingleNode("/tagA");
var nodeB = nodeA.SelectSingleNode("tagB");
nodeA.RemoveChild(nodeB);

To remove (possibly) multiple tagB nodes in unknown positions, you may try:

var bees = xmlDoc.SelectNodes("//tagB");
foreach (XmlNode bee in bees) {
    var parent = bee.ParentNode;
    parent.RemoveChild(bee);
}

2 Comments

Thanks for the answer,the problem is that <tagB> is on different places each time, cant I find it without knowing all the parents?
'//tagB' is a greedy xpath meaning; take any element anywhere'. Thus it will work even if tagB is nested multiple elements deep on different levels.

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.