How to add Namespace and Declaration in XDocument - c#

I am creating xml in C#, and want to add Namespace and Declaration . My xml as below:
XNamespace ns = "http://ab.com//abc";
XDocument myXML = new XDocument(
new XDeclaration("1.0","utf-8","yes"),
new XElement(ns + "Root",
new XElement("abc","1")))
This will add xmlns="" at both Root level and child element abc level as well.
<Root xmlns="http://ab.com/ab">
<abc xmlns=""></abc>
</Root>
But I want it in only Root level not in child level like below:
<Root xmlns="http://ab.com/ab">
<abc></abc>
</Root>
and how to add Declaration at Top, my code not showing Declaration after run.
Please help me to get the complete xml as
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Root xmlns="http://ab.com/ab">
<abc></abc>
</Root>

You need to use the same namespace in your child elements:
XDocument myXML = new XDocument(
new XDeclaration("1.0","utf-8","yes"),
new XElement(ns + "Root",
new XElement(ns + "abc", "1")))
If you just use "abc" this will be converted to an XName with no Namespace. This then results in an xmlns="" attribute being added so the fully qualified element name for abc would be resolved as such.
By setting the name to ns + "abc" no xmlns attribute will be added when converted to string as the default namespace of http://ab.com/ab is inherited from Root.
If you wanted to simply 'inherit' the namespace then you wouldn't be able to do this in such a fluent way. You'd have create the XName using the namespace of the parent element, for example:
var root = new XElement(ns + "Root");
root.Add(new XElement(root.Name.Namespace + "abc", "1"));
Regarding the declaration, XDocument doesn't include this when calling ToString. It will if you use Save to write to a Stream, TextWriter, or if you supply an XmlWriter that doesn't have OmitXmlDeclaration = true in its XmlWriterSettings.
If you wanted to just get the string, this question has an answer with a nifty extension method using a StringWriter.

Use the namespace on all elements you create:
XDocument myXML = new XDocument(
new XDeclaration("1.0","utf-8","yes"),
new XElement(ns + "Root",
new XElement(ns + "abc","1")))

Related

Error when redefining a different xml Namespace to an existing alias using XElement with System.Xml.Linq

I try programming the following xml document (simplified) as code:
<P xmlns="http://schemas.microsoft.com/x/2010/manifest"
xmlns:ab="http://schemas.microsoft.com/a/2010/manifest"
xmlns:ac="http://schemas.microsoft.com/a/2013/manifest">
<ab:Ex xmlns:ab="http://schemas.microsoft.com/a/2013/manifest">
</ab:Ex>
</P>
Now an element redefines the namespace:
xmlns:ab="http://schemas.microsoft.com/a/2013/manifest".
how do I get the element into my program? It is obviously valid because I can load the xml file like this:
Add(new XAttribute (XNamespace.Xmlns + "ab")
I get the error message:
System.Xml.XmlException: 'The prefix 'ab' cannot be redefined from 'http://schemas.microsoft.com/a/2010/manifest' to 'http://schemas.microsoft.com/a/2013/manifest' within the same start element tag.'
Actually logical (redefinition) but when I load the document, the element is accepted.
using System.Xml.Linq;
namespace xmltest
{
class Program
{
static void Main(string[] args)
{
//Load
XDocument doc1 = XDocument.Load(#"c:\simple.xml", LoadOptions.None);
System.Console.WriteLine(doc1.ToString());
//Create new
XNamespace ab = "http://schemas.microsoft.com/a/2010/manifest";
XNamespace nsx = "http://schemas.microsoft.com/x/2010/manifest";
XDocument doc2 = new XDocument(new XDeclaration("1.0", "utf-8", ""),
new XElement(nsx + "P"));
doc2.Element(nsx + "P").Add(new XAttribute("xmlns",
"http://schemas.microsoft.com/x/2010/manifest"));
doc2.Element(nsx + "P").Add(new XAttribute(XNamespace.Xmlns + "ab",
"http://schemas.microsoft.com/a/2010/manifest"));
doc2.Element(nsx + "P").Add(new XAttribute(XNamespace.Xmlns + "ac",
"http://schemas.microsoft.com/a/2013/manifest"));
XElement xml = new XElement(ab + "Ex");
//--> Below does not work work
xml.Add(new XAttribute(XNamespace.Xmlns + "ab",
"http://schemas.microsoft.com/a/2013/manifest"));
doc2.Element(nsx + "P").Add(xml);
System.Console.WriteLine(doc2.ToString());
}
}
}
Anybody have any idea how to solve this problem?
In theory, because
<ab:Ex xmlns:ab="http://schemas.microsoft.com/a/2013/manifest">
actually means that Ex is to be defined in the new namespace (2013), you can get what you want by defining Ex in the new namespace, i.e. something like:
XNamespace abOld = "http://schemas.microsoft.com/a/2010/manifest";
XNamespace abNew = "http://schemas.microsoft.com/a/2013/manifest";
XNamespace nsx = ...
XElement xml = new XElement(abNew + "Ex");
xml.Add(new XAttribute(XNamespace.Xmlns + "ab",
"http://schemas.microsoft.com/a/2013/manifest"));
However, repurposing the alias of an existing namespace just so that you can use the same alias is going to be really confusing to future maintenance - as the alias leaves scope, it will revert to it's old definition. I would recommend that you at least create different, unique aliases for the 2010 and 2013 namespaces.
Also, unless the intended consumer of the Xml was buggy, and required specific aliases or namespace scopes, I would generally avoid micro-managing the namespace aliasing and namespace scoping - let Linq to Xml manage that for you.
For instance, how about just:
XNamespace abOld = "http://schemas.microsoft.com/a/2010/manifest";
XNamespace abNew = "http://schemas.microsoft.com/a/2013/manifest";
// Build up the document by providing element, attribute + applicable namespaces:
var root = new XElement(abOld + "P",
new XElement(abNew + "Ex"));

Add xsi:type to my XML document

I have a code to extract an XML document type using this web service method
XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
XAttribute attribute = new XAttribute(xsi + "type", "xsd:string");
XElement node_user_id = new XElement("user_id", attribute, user.code);
XDocument doc = new XDocument(new XElement("ranzcp_user", new XAttribute(XNamespace.Xmlns + "ns1", "urn:logon"), node_user_id));
XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(elem.ToString());
With the above code i was able to extract an xml document exactly like this :
<ranzcp_user xmlns:ns1="urn:logon">
<user_id xmlns:p3="http://www.w3.org/2001/XMLSchema-instance" p3:type="xsd:string">12345678</user_id>
</ranzcp_user>
But what i really need to have is this :
<ranzcp_user xmlns:ns1="urn:logon">
<user_id xsi:type="xsd:string">12345678</user_id>
</ranzcp_user>
Is there any way i could get the format i need for the xml, and second do the xsi:type="xsd:string" attribute was neccessary when the xml data was parsed?
TIA!
You could explicitly define the namespace prefix so you use the canonical xsi rather than p3:
var doc = new XDocument(
new XElement("ranzcp_user",
new XAttribute(XNamespace.Xmlns + "ns1", "urn:logon"),
new XAttribute(XNamespace.Xmlns + "xsi", xsi),
new XElement("user_id", 12345678,
new XAttribute(xsi + "type", "xsd:string")
)
)
);
See this fiddle. This gives you:
<ranzcp_user xmlns:ns1="urn:logon" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<user_id xsi:type="xsd:string">12345678</user_id>
</ranzcp_user>
But, as has been said, removing the namespace prefix entirely would result in invalid XML - no conforming processor will let you create it or read it without errors.
Could it be that the 'required' XML has this prefix declared in one of the parent elements? If not, I'd suggest it's a mistake and you should investigate this before spending time trying to remove the attribute. I suspect you'd end up undoing all that effort when the consumer works out the XML is invalid.

how to handle namespaces in the root element

I am reading from a csv file and transferring the data to an xml file using XmlSerializer in c#.But now I am facing a problem with the namespaces in the root element.My required xml should be in the following format.
<?xml version="1.0" encoding="ASCII"?>
<abc:Country xmi:version="2.0"
xmlns:xmi="http://www.omg.org/XMI"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:abc="some url">
<Person></Person>
</abc:Country>
But I am getting my output in this format:
<?xml version="1.0" encoding="ASCII"?>
<Country xmi:version="2.0"
xmlns:xmi="http://www.omg.org/XMI"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Person></Person>
</Country>
I want the namespace of abc to be included in the root and then also "abc" should prefix only my root element i.e "Country". I tried using various options mentioned online but none of them actually worked for me.When i use the XmlSerializerNamespaces and overload my Serialiser class all opther namespaces disappear.So could you let me know how I could achieve this.
Is it important to use XmlSerializer? This sort of thing is pretty easy to do with XDocument instead. Something like this:
var document = new XDocument();
XNamespace abcns = "http://some/url/abc";
XNamespace xmins = "http://www.omg.org/XMI";
XNamespace xsins = "http://www.w3.org/2001/XMLSchema-instance";
var element = new XElement(abcns + "Country",
new XAttribute(XNamespace.Xmlns + "abc", abcns),
new XAttribute(XNamespace.Xmlns + "xmi", xmins),
new XAttribute(XNamespace.Xmlns + "xsi", xsins),
new XAttribute(xmins + "version", "2.0"),
new XElement("Person"));
document.Add(element);
We can use the following to include multiple namespaces in the root element of the xml:
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("xmi", "http://www.omg.org/XMI");
ns.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");
ns.Add("abc", "some url");
XmlSerializer serializer = new XmlSerializer(typeof(Country));
TextWriter textWriter = new StreamWriter(#"C:\test.xml", true, Encoding.ASCII);
serializer.Serialize(textWriter, country, ns);
"country" would be the object that you would be creating for the class "Country"(root element of your xml).

How do I get rid of empty namespaces "xmlns=""" in subelements?

I have this
XNamespace ns = "http://something0.com";
XNamespace xsi = "http://something1.com";
XNamespace schemaLocation = "http://something3.com";
XDocument doc2 = new XDocument(
new XElement(ns.GetName("Foo"),
new XAttribute(XNamespace.Xmlns + "xsi", xsi),
new XAttribute(xsi.GetName("schemaLocation"), schemaLocation),
new XElement("ReportHeader", GetSection()),
GetGroup()
)
);
It gives
<?xml version="1.0" encoding="utf-8"?>
<Foo xmlns:xsi="http://something1.com"
xsi:schemaLocation="http://something3.com"
xmlns="http://something0.com">
<ReportHeader xmlns="">
...
</ReportHeader>
<Group xmlns="">
...
</Group>
</Foo>
But I wan't this result, how can it be done? (Notice the xmlns=""is missing..)
<?xml version="1.0" encoding="utf-8"?>
<Foo xmlns:xsi="http://something1.com"
xsi:schemaLocation="http://something3.com"
xmlns="http://something0.com">
<ReportHeader>
...
</ReportHeader>
<Group>
...
</Group>
</Foo>
Your problem here is that you are setting the default namespace for the document to "http://something0.com", but then appending elements that are not in this namespace - they are in the empty namespace.
Your document states it has a default namespace of xmlns="http://something0.com", but then you append elements which are in the empty namespace (because you didn't supply their namespace when you appended them) - so they are all getting explicitly marked with xmlns='' to show they are not in the default namespace of the document.
This means there are two solutions to getting rid of the xmlns="", but they have different meanings:
1) If you mean you definitely want the xmlns="http://something0.com" at the root element (specifying the default namespace for the document) - then to "disappear" the xmlns="" you need to you need to supply this namespace when creating the elements:
// create a ReportHeader element in the namespace http://something0.com
new XElement(ns + "ReportHeader", GetSection())
2) If these elements are not meant to be in the namespace
"http://something0.com", then you mustn't add it as the default at
the top of the document (the xmlns="http://something0.com" bit on
the root element).
XDocument doc2 = new XDocument(
new XElement("foo", // note - just the element name, rather s.GetName("Foo")
new XAttribute(XNamespace.Xmlns + "xsi", xsi),
The sample output you expect, suggests the former of these two choices.

Add multiple namespacs with same address to XDocument

I need to add multiple namespaces to the xdocument with same address (C#)
<root xmlns:f="urn://xml.voodoo.net/vd/formating-1.0" xmlns="urn://xml.voodoo.net/vd/formating-1.0">
<a:something>stuff and more stuff</a:something>
</root>
if i add using the below code.. it shows only xmlns:f
XNamespace defaultNS = "urn://xml.voodoo.net/vd/formating-1.0";
XNamespace f = "urn://xml.voodoo.net/vd/formating-1.0";
XElement rootElement = new XElement(defaultNS + "root",
new XAttribute(XNamespace.Xmlns + "f", f.NamespaceName),
how to show 2 namespaces?? is it even possible?
var doc = new XDocument(
new XElement(defaultNS + "root",
new XAttribute(XNamespace.Xmlns + "f", defaultNS),
new XAttribute("xmlns", defaultNS),
new XElement(defaultNS + "something",
new XAttribute(XNamespace.Xmlns + "f", defaultNS), "stuff and more stuff")
)
);
Desired output:
<root xmlns:f="urn://xml.voodoo.net/vd/formating-1.0" xmlns="urn://xml.voodoo.net/vd/formating-1.0">
<f:something xmlns:f="urn://xml.voodoo.net/vd/formating-1.0">stuff and more stuff</f:something>
</root>
Your XML example is incorrect, the 'f' namespace is not used, whereas there is an 'a' namespace present.
Your C# code does not match your XML, it creates an element with an attribute.
Anyhow, a namespace definitions within an XML document only makes sense if you actually use it. If you create an XML document via C# code, it will generate XML which is semantically correct, yet might not match the syntax of your example.

Categories