I'm using Linq to XML to create a new XML file. Some part of the file do I get from an existing XML file. I use the following code for this.
var v2 = new XDocument(
new XDeclaration("1.0", "utf-16", ""),
new XComment(string.Format("Converted from version 1. Date: {0}", DateTime.Now)),
new XElement(ns + "keyem",
new XAttribute(XNamespace.Xmlns + "xsd", xsd.NamespaceName),
new XAttribute(XNamespace.Xmlns + "xsi", xsi.NamespaceName),
new XAttribute(xsi + "schemaLocation", schemaLocation.NamespaceName),
new XAttribute("version", "2"),
new XAttribute("description", description),
new XElement(ns + "layout",
new XAttribute("type", type),
new XAttribute("height", height),
new XAttribute("width", width),
settings.Root) // XML from an existing file
The problem is that it adds xmlns = "" the first element from the existing file.
The result is:
<?xml version="1.0" encoding="utf-16"?>
<foo
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://tempuri.org/KeyEmFileSchema.xsd KeyEmFileSchema.xsd"
xmlns="http://tempuri.org/KeyEmFileSchema.xsd">
<settings xmlns="">
...
</settings>
</foo>
The XML file I'm reading from looks like this, but I can change it if needed
<?xml version="1.0" encoding="utf-16"?>
<settings>
<colormaps>
<colormap color="Gray" textcolor="Black"/>
<colormap color="DarkGray" textcolor="White"/>
<colormap color="Black" textcolor="White"/>
<colormap color="Cyan" textcolor="Black"/>
</colormaps>
<macromaps>
<macromap pattern="^@([0-9A-F]{2})\|([0-9A-F]{2})$" replace="{ESC}$1{ESC}$2{MOUSERESET}"/>
<macromap pattern="^\$([0-9A-F]{2})\|([0-9A-F]{2})$" replace="{USERCLICK}{ESC}$1{ESC}$2{MOUSERESET}"/>
<macromap pattern="^\$([0-9A-F]{2})$" replace="{USERCLICK}{ESC}$1"/>
</macromaps>
<keydefault color="Cyan"/>
<groupdefault color="DarkGray"/>
</settings>
The xmlns attribute in the first <table> element gives the h: prefix a qualified namespace. The xmlns attribute in the second <table> element gives the f: prefix a qualified namespace. When a namespace is defined for an element, all child elements with the same prefix are associated with the same namespace.
XElement element = XElement. Load(var); c#
The namespace URI is what allows us to identify uniquely the namespace. It is also called the namespace name. If you use an URL, you will take advantage of the uniqueness of domain names in the domain name system (DNS).
The XElement class represents an XML element in XLinq. The code creaes a root node called Authors and adds children Author nodes. The XAttribute class represents an attribute of an element. XElement. Save method saves the contents of XElement to a XML file.
You're seeing this because the settings element (presumably coming from your document) does not live in this namespace. It lives in the default/null-uri namespace.
You would need to transform your input document in order to change it's namespace.
This somewhat simplified example take your xml file and places it into another document but, before it does so, it changes the namespace of every element in that xml file to that of your target document...
static void ProcessXmlFile()
{
XNamespace ns = "http://tempuri.org/KeyEmFileSchema.xsd/";
// load the xml document
XElement settings = XElement.Load("data.xml");
// shift ALL elements in the settings document into the target namespace
foreach (XElement e in settings.DescendantsAndSelf())
{
e.Name = ns + e.Name.LocalName;
}
// write the output document
var file = new XDocument(new XElement(ns + "foo",
settings));
Console.Write(file.ToString());
}
The result of which this...
<foo xmlns="http://tempuri.org/KeyEmFileSchema.xsd/">
<settings>
<colormaps>
<colormap color="Gray" textcolor="Black" />
<colormap color="DarkGray" textcolor="White" />
<colormap color="Black" textcolor="White" />
<colormap color="Cyan" textcolor="Black" />
</colormaps>
<macromaps>
<macromap pattern="^@([0-9A-F]{2})\|([0-9A-F]{2})$" replace="{ESC}$1{ESC}$2{MOUSERESET}" />
<macromap pattern="^\$([0-9A-F]{2})\|([0-9A-F]{2})$" replace="{USERCLICK}{ESC}$1{ESC}$2{MOUSERESET}" />
<macromap pattern="^\$([0-9A-F]{2})$" replace="{USERCLICK}{ESC}$1" />
</macromaps>
<keydefault color="Cyan" />
<groupdefault color="DarkGray" />
</settings>
</foo>
As you can see, the settings element is now in the same namespace as the foo element. This is essentially a quick and dirty xml transform, and clearly it doesn't respect any namespaces in the xml doc you're importing. But this might be what you're after, or might at least form the basis of something more robust.
You could write an extension method for this. This method has a return value so it supports chaining, but also changes transformation of the original so it can be used without assignment.
public static XElement EnsureNamespaceExists(this XElement xElement, XNamespace xNamespace)
{
string nodeName = xElement.Name.LocalName;
if (!xElement.HasAttribute("xmlns"))
{
foreach (XElement tmpElement in xElement.DescendantsAndSelf())
{
tmpElement.Name = xNamespace + tmpElement.Name.LocalName;
}
xElement = new XElement(xNamespace + nodeName, xElement.FirstNode);
}
return xElement;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With