I attempting to add a new "PropertyGroup" element to the following XML file
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<ProjectGuid>{00AA7ECA-95A0-0000-0000-AD4D2E056BFE}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>testnS</RootNamespace>
<AssemblyName>testname</AssemblyName>
<PluginId>4B84E5C0-EC2B-4C0C-8B8E-3FAEB09F74C6</PluginId>
</PropertyGroup>
</Project>
The code I am using is as follows (note there is other logic that has been removed) :
XmlTextReader reader = new XmlTextReader(filename);
XmlDocument doc = new XmlDocument();
doc.Load(reader);
reader.Close();
XmlNamespaceManager ns = new XmlNamespaceManager(doc.NameTable);
ns.AddNamespace("x", "http://schemas.microsoft.com/developer/msbuild/2003");
XmlElement root = doc.DocumentElement;
XmlNode refNode = root.SelectSingleNode("x:Project", ns);
root.SelectSingleNode("Project", ns);
XmlElement newElement = doc.CreateElement("PropertyGroup", "http://schemas.microsoft.com/developer/msbuild/2003");
newElement.InnerXml = "<value>test</value>";
root.InsertAfter(newElement, refNode);
doc.Save(filename);
This yields the following new element in the XML document :
<PropertyGroup>
<value xmlns="">test</value>
</PropertyGroup>
How do I get rid of the namespace declaration on the element?
You need to specify the XML namespace for all elements you add to the DOM:
XmlNamespaceManager ns = new XmlNamespaceManager(doc.NameTable);
ns.AddNamespace("x", "http://schemas.microsoft.com/developer/msbuild/2003");
XmlElement root = doc.DocumentElement;
XmlNode refNode = root.SelectSingleNode("x:Project", ns);
XmlElement newElement = doc.CreateElement(
"PropertyGroup",
"http://schemas.microsoft.com/developer/msbuild/2003");
var value = newElement.AppendChild(doc.CreateElement(
"value",
"http://schemas.microsoft.com/developer/msbuild/2003"));
value.AppendChild(doc.CreateTextNode("test"));
root.InsertAfter(newElement, refNode);
If you don't do so for any element (or if you use InnerXml
like that), that element will get the dreaded empty namespace.
The reason this is happening is that you've defined the default namespace for the document to be "http://schemas.microsoft.com/developer/msbuild/2003" by having the namespace definition on the root node:
xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
You then proceed to add an element which is in no namespace (the 'null' namespace) to the document. This has to be qualified with
xmlns=""
because if it wasn't it would mean that the new element was in the previously mentioned Microsoft namespace - which it isn't (or rather - which you haven't asked it to be).
So either:
you actually want the new element to
be in the Microsoft namespace - in
which case you need to say so. The
easiest way is to use createElement
and supply the namespace, although
you can probably state it explicitly
with an xmlns attribute on your
InnerXml (which is not a particularly
nice way of adding nodes).
You really do want this element in
the null namespace, in which case you
are probably better of qualifying all
the other nodes that are not in the
null namespace with a namespace
prefix.
I suspect you want the former.
A quick overview on namespaces can be found here.
To avoid extra xmlns=""
attribute in newly created elements you can pass root namespace as an argument:
$child = $doc.CreateElement("value", $doc.DocumentElement.NamespaceURI);
$res = $doc.PropertyGroup.AppendChild($child); # res here to avoid extra output
which will result in
<PropertyGroup>
<value></value>
</PropertyGroup>