System.Xml Hacking (AppendXml vs. InnerXml)
I was spending some time composing Soap Messages using System.Xml, but I found a strange behavior of System.Xml while adding nodes to an existing XmlDocument.
I have an empty soap envelope like this:
string soapEnvelope = "<s:env xmlns:s='soap'><s:body /></s:env>";
What I want is to add the method payload from the next information:
string methodName = "m";
string ns="urn:ns";
string methodBody = "<name>rido</name>";
My first attempt was a mix between AppendChild and InnerXml
XmlDocument doc = new XmlDocument();
doc.LoadXml(soapEnvelope);
XmlElement methodNode = doc.CreateElement(methodName, ns);
methodNode.InnerXml = methodBody;
XmlNode body = doc.GetElementsByTagName("s:body")[0];
body.AppendChild(methodNode);
However the result output was
<s:env xmlns:s="soap">
<s:body>
<m xmlns="urn:ns">
<name xmlns="">rido</name>
</m>
</s:body>
</s:env>
Note the empty namespace declaration in the name element, and the bad news is that ASP.Net needs the namespace information to deserialize the request message, so I have to hack System.Xml to avoid this behavior.
I take a look to news://microsoft.public.dotnet.xml and I only a found a few messages talking about how to remove the attribute once the final message is composed, but I would like to avoid the empty namespace (xmlns=””) while composing the doc. After playing a little bit with the API I found the solution:
Instead of creating the method element with AppendChild, I’m going to manually build the whole method element in a string, and assign it to the body InnerXml property:
XmlDocument doc = new XmlDocument();
doc.LoadXml(soapEnvelope);
XmlNode body = doc.GetElementsByTagName("s:body")[0];
string methodXml = String.Format("<{0} xmlns='{1}'>{2}</{0}>",
methodName, ns, methodBody);
body.InnerXml = methodXml;
Now it works…
Comments
- Anonymous
December 07, 2004
I figured this out....<br><br>(doc is an XmlDocument) <br><br>XmlElement root = doc.DocumentElement;<br><br> string defaultns = string.Empty;// = "urn:schemas-microsoft-com:office:spreadsheet";<br><br> defaultns = root.NamespaceURI;<br><br> XmlElement rowElem = doc.CreateElement ("Row" , defaultns);<br><br>This got rid of the "empty namespace". What is happening is that because their is ~~already a default namespace, its putting one in for the UnIdentified (namespace) for the new XmlElement.<br><br>C# code is above.<br><br>..