How to specify an xmlns for XDocument? - c#

I tried:
textBox1.Text = new XDocument(new XDeclaration("1.0", "UTF-8", "yes"),
new XElement("root1", new XAttribute( "xmlns", #"http://example.com"), new XElement("a", "b"))
).ToString();
But I get:
The prefix '' cannot be redefined from '' to 'http://example.com' within the same start element tag.
I also tried substituting (according to an answer I found) :
XAttribute(XNamespace.Xmlns,...
But got an error as well.
Note: I'm not trying to have more than one xmlns in the document.

The way the XDocument API works with namespace-scoped names is as XName instances. These are fairly easy to work with, as long as you accept that an XML name isn't just a string, but a scoped identifier. Here's how I do it:
var ns = XNamespace.Get("http://example.com");
var doc = new XDocument(new XDeclaration("1.0", "utf-8", null));
var root = new XElement(ns + "root1", new XElement(ns + "a", "b"));
doc.Add(root);
Result:
<root1 xmlns="http://example.com">
<a>b</a>
</root1>
Note the + operator is overloaded to accept an XNamespace and a String to result in and XName instance.

Related

Issue creating XML doc from Dictionary

My intention is to iterate through my lovely dictionary (both key and value are strings) and create an xml file from it.
I get the error on the last line (saving the xml).
"InvalidOperationException was unhandled
Token EndDocument in state Document would result in an invalid XML document."
Looking through this using breakpoints it would seem that at reaching the end of this, only the initial bit (outside the for each loop) has been done..
I'm half asking what silly mistake I've made, I'm partly asking if there's a more eloquent way of doing this.
Sorry if I've missed anything, let me know if i have, will add.
XDocument xData = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"));
foreach (KeyValuePair<string, string> kvp in inputDictionary)
{
xData.Element(valuesName).Add(
new XElement(valuesName,
new XAttribute("key", kvp.Key),
new XAttribute("value", kvp.Value)));
}
xData.Save("C:\\xData.xml");
Currently you're adding multiple elements directly to the document - so you'd end up with either no root elements (if the dictionary is empty) or potentially multiple root elements (if there's more than one entry in the dictionary). You want a root element, and then your dictionary elements under that. Additionally, you're trying to find an element called valuesName without ever adding anything, so you'll actually get a NullReferenceException if there are any dictionary entries.
Fortunately, it's even easier than you've made it, because you can just use LINQ to transform your dictionary into a sequence of elements and put that in the doc.
var doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("root",
inputDictionary.Select(kvp => new XElement(valuesName,
new XAttribute("key", kvp.Key),
new XAttribute("value", kvp.Value)))));
doc.Save(#"c:\data.xml");
Complete sample app:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
class Test
{
static void Main()
{
XName valuesName = "entry";
var dictionary = new Dictionary<string, string>
{
{ "A", "B" },
{ "Foo", "Bar" }
};
var doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("root",
dictionary.Select(kvp => new XElement(valuesName,
new XAttribute("key", kvp.Key),
new XAttribute("value", kvp.Value)))));
doc.Save("test.xml");
}
}
Output (order of entries is not guaranteed):
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<root>
<entry key="A" value="B" />
<entry key="Foo" value="Bar" />
</root>
An alternative breakdown for this would be:
var elements = inputDictionary.Select(kvp => new XElement(valuesName,
new XAttribute("key", kvp.Key),
new XAttribute("value", kvp.Value)));
var doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("root", elements));
You may find this simpler to read.
try the following
XDocument xData = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"));
XElement myXml = new XElement("paramList");// make sure your root and your descendents do not shre same name
foreach (var entry in MyList)
{
myXml.Add(new XElement(valuesName,
new XElement("key", entry.key),
new XElement("value", entry.Value)
));
xData.Add(myXml);

Little help using XmlTextWriter on writing "xhtml:link" element of sitemap.xml

Hello I'm trying to write a string like :
<xhtml:link rel="alternate" hreflang="de" href="http://www.example.com/de" />
using XmlTextWriter class
I've tried this piece of code:
// Write Alternative links
_writer.WriteStartElement("xhtml:link");
_writer.WriteAttributeString("rel","alternate");
_writer.WriteAttributeString("hreflang", "de");
_writer.WriteAttributeString("href", "http://example.com/de");
_writer.WriteEndElement();
Which generates this error:
Namespace prefix xhtml on link is not defined
But I don't need any namespaces provided for xhtml:link
Question: How to achieve the string that I need using XmlTextWriter?
Update 1: I have changed to LINQ to XML
But for now I have another problem... For the beginning I'll show the code:
private readonly XNamespace nsXhtml = "http://www.w3.org/1999/xhtml";
private readonly XNamespace nsSitemap = "http://www.sitemaps.org/schemas/sitemap/0.9";
private readonly XNamespace nsXsi = "http://www.w3.org/2001/XMLSchema-instance";
private readonly XNamespace nsLocation = "http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd";
public XDocument Generate()
{
var sitemap = new XDocument(new XDeclaration("1.0", "utf-8", "yes"));
var urlSet = new XElement(nsSitemap + "urlset",
new XAttribute("xmlns", nsSitemap),
new XAttribute(XNamespace.Xmlns + "xhtml", nsXhtml),
new XAttribute(XNamespace.Xmlns + "xsi", nsXsi),
new XAttribute(nsXsi + "schemaLocation", nsLocation),
from node in GenerateUrlNodes() // Provides a collection of "objects", actually it doesn't matter since we anyway convert them to XElement below...
select WriteUrlLocation(node.Url,node.UpdateFrequency,node.LastModified));
sitemap.Add(urlSet);
return sitemap;
}
protected XElement WriteUrlLocation(string url, UpdateFrequency updateFrequency, DateTime lastUpdated)
{
var urlNode = new XElement(nsSitemap + "url",
new XElement(nsSitemap + "loc", url),
new XElement(nsSitemap + "changefreq", updateFrequency),
new XElement(nsSitemap + "lastmod", lastUpdated)
);
var linkNode = new XElement(nsXhtml + "link",
new XAttribute("rel", "alternate"),
new XAttribute("hreflang", "de"),
new XAttribute("href", "http://example.com/de"));
urlNode.Add(linkNode);
return urlNode;
}
The problem is that When I inspect the Generated sitemap at Controller:
public ActionResult Sitemap()
{
var sitemap = _sitemapGenerator.Generate().ToString();
return Content(sitemap,"text/xml");
}
The whole xml is not as expected and, the <xhtml:link> element is rendered with a non-empty closing tag (thus I don't know if this is a problem here) .. Look at the image please
Update 2: Solved! Seems that the XML structure is valid but the browser is not displaying it right...
You should change to use a different overload of XmlWriter.StartElement. For example:
_writer.WriteStartElement("link", "http://www.w3.org/1999/xhtml");
That assumes you've already got a prefix alias of xhtml for the namespace http://www.w3.org/1999/xhtml. I'd still recommend shifting to use LINQ to XML as soon as you can though... XmlWriter is great for cases where you really need to stream the data (e.g. when it's huge) but otherwise, LINQ to XML makes things a lot easier:
XNamespace xhtml = "http://www.w3.org/1999/xhtml";
var element = new XElement(xhtml + "link",
new XAttribute("rel", "alternate"),
new XAttribute("hreflang", "de"),
new XAttribute("href", "http://example.com/de"));
parent.Add(element);
If you will use XML Writer and write this
<xhtml:link rel="alternate" hreflang="en" href="www.yoursite.com" />
you can choose this code for .NET CORE 2.0:
foreach (SitemapNodeAlternate a in alternate)
{
MyWriter.WriteStartElement("xhtml", "link", null);
MyWriter.WriteAttributeString("rel", "alternate");
MyWriter.WriteAttributeString("href", a.href);
MyWriter.WriteAttributeString("hreflang", a.hreflang);
MyWriter.WriteEndElement();
}

Linq to XML, C#

I have an xml in XDocument object (LINQ to XML). I need to add the namespace to each Xelement/node in the Xdocument.
I dont want to add in the below way. beceause i already have the xml in xdoc.
XDocument xDoc = new XDocument(
new XElement(ns + "root",
new XElement(ns + "person",
new XAttribute("id", 1),
new XElement(ns + "firstname", "jack"),
Below is the format i have
<root>
<person>1</person>
<firstname>jack</firstname>
</root>
I want to convert it to this below format
<emp:root>
<emp:person>1</emp:person>
<emp:firstname>jack</emp:firstname>
</emp:root>
foreach (var node in xDoc.Descendants())
{
node.Name = ns + node.Name.LocalName;
}
That should work:
Side note the namespace will only appear on the root node.

Create XML doc by LINQ, add xmlns,xmlns:xsi to it

I try to create an GPX XML document by LINQ to XML.
Everything works great, except adding xmlns, xmlns:xsi attributes to the doc. By trying it different way I get different exceptions.
My code:
XDocument xDoc = new XDocument(
new XDeclaration("1.0", "UTF-8", "no"),
new XElement("gpx",
new XAttribute("creator", "XML tester"),
new XAttribute("version","1.1"),
new XElement("wpt",
new XAttribute("lat","7.0"),
new XAttribute("lon","19.0"),
new XElement("name","test"),
new XElement("sym","Car"))
));
The output should also contain this:
xmlns="http://www.topografix.com/GPX/1/1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"
How can I add it by Linq to XML? I tried several ways but it does not work, exceptions during compile time.
See How to: Control Namespace Prefixes. You could use code like this:
XNamespace ns = "http://www.topografix.com/GPX/1/1";
XNamespace xsiNs = "http://www.w3.org/2001/XMLSchema-instance";
XDocument xDoc = new XDocument(
new XDeclaration("1.0", "UTF-8", "no"),
new XElement(ns + "gpx",
new XAttribute(XNamespace.Xmlns + "xsi", xsiNs),
new XAttribute(xsiNs + "schemaLocation",
"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"),
new XAttribute("creator", "XML tester"),
new XAttribute("version","1.1"),
new XElement(ns + "wpt",
new XAttribute("lat","7.0"),
new XAttribute("lon","19.0"),
new XElement(ns + "name","test"),
new XElement(ns + "sym","Car"))
));
You have to specify the namespace for each element, because that's what using xmlns this way means.
From http://www.falconwebtech.com/post/2010/06/03/Adding-schemaLocation-attribute-to-XElement-in-LINQ-to-XML.aspx:
To generate the following root node and namespaces:
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:SchemaLocation="http://www.foo.bar someSchema.xsd"
xmlns="http://www.foo.bar" >
</root>
Use the following code:
XNamespace xsi = XNamespace.Get("http://www.w3.org/2001/XMLSchema-instance");
XNamespace defaultNamespace = XNamespace.Get("http://www.foo.bar");
XElement doc = new XElement(
new XElement(defaultNamespace + "root",
new XAttribute(XNamespace.Xmlns + "xsi", xsi.NamespaceName),
new XAttribute(xsi + "schemaLocation", "http://www.foo.bar someSchema.xsd")
)
);
Be aware - if you want to add elements to the document, you need to specify the defaultNamespace in the element name or you will get xmlns="" added to your element. For example, to add a child element "count" to the above document, use:
xdoc.Add(new XElement(defaultNamespace + "count", 0)

How do I add multiple Namespace declarations to an XDocument?

I'm using an XDocument to build an Xml document in a known structure. The structure I am trying to build is as follows:
<request xmlns:ns4="http://www.example.com/a" xmlns:ns3="http://www.example.com/b" xmlns:ns2="http://www.example.com/c" >
<requestId>d78d4056-a831-4c7d-a357-d14402f623fc</requestId>
....
</request>
Notice the "xmlns:nsX" attributes.
I am trying, without success, to add these attributes to my "request" element.
XNamespace ns4 = XNamespace.Get("http://www.example.com/a");
XNamespace ns3 = XNamespace.Get("http://www.example.com/b");
XNamespace ns2 = XNamespace.Get("http://www.example.com/c");
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "no"),
new XElement("request",
new XAttribute("ns4", ns4),
new XAttribute("ns3", ns3),
new XAttribute("ns2", ns2),
new XElement("requestId", Guid.NewGuid())
)
);
However, this produces the following:
<request ns4="http://www.example.com/a" ns3="http://www.example.com/b" ns2="http://www.example.com/c">
<requestId>38b07cfb-5e41-4d9a-97c8-4740c0432f11</requestId>
</request>
How do I add the namespace declarations correctly?
Do you mean:
new XAttribute(XNamespace.Xmlns + "ns4", ns4),
new XAttribute(XNamespace.Xmlns + "ns3", ns3),
new XAttribute(XNamespace.Xmlns + "ns2", ns2),

Categories

Resources