Creating namespace for XML element - c#

I have problem with adding new node (with namespace) to my xml document which is used to generating xaml. I'm doing it like this:
XmlElement richTextColumns = xmlDoc.CreateElement("local2:RichTextColumns");
but i receive error 0xC00CE01D (while calling xmlDoc.getxml). I have tried adding attribute xmlns:local2="using:App2.Common" to xmlDoc:
var att = xmlDoc.CreateAttribute("xmlns:local2");
att.InnerText = "using:Dictionary.Common";
xmlDoc.Attributes.SetNamedItem(att);
it results in this error
Object reference not set to an instance of an object.
Thank you in advance :)

If you'd like to create an element with a specific namespace use this call:
xmlDoc.CreateElementNS("using:Dictionary.Common", "local2:elementName")

According to http://msdn.microsoft.com/en-us/library/aa335908(v=vs.71), the CreateAttribute method with a single parameter does not set the namespace, but the name of the element. Try to use one of the other permutations of this method.

You can create an element as you would typically do and then load the document back and add the namespace atribute you are looking to add.
XmlDocument doc = new XmlDocument();
    doc.LoadXml("link to yuor xml");
XNamespace xmlns = "local2";
public static void SetDefaultXmlNamespace(XElement xelem, XNamespace xmlns)
{
foreach(var e in xelem.Elements())
e.SetDefaultXmlNamespace(xmlns);
}
doc.Root.SetDefaultXmlNamespace("local2")

Related

XML adding child element to existing XML element

I have the following XML element:
<ctext:RootAugmentation>
</ctext:RootAugmentation>
I would like to add the following element inside the above element:
<ctext:DetailsText>Example</ctext:DetailsText>
I have the following code:
string filename = #"C:\test.xml";
XmlDocument doc = new XmlDocument();
doc.LoadXml(File.ReadAllText(filename));
XmlNodeList elemList = doc.GetElementsByTagName("ctext:RootAugmentation");
XmlElement detailsElement = doc.CreateElement("ctext:DetailsText");
detailsElement.InnerText = "Example";
if (elemList.Count == 1)
{
for (int i = 0; i < elemList.Count; i++)
{
Console.WriteLine(elemList[i].InnerText);
elemList[i].AppendChild(detailsElement);
}
doc.Save(filename);
}
else
{
// update existing "ctext:DetailsText" value
}
I'm able to add the child element but tags are wrong:
<ctext:RootAugmentation>
<DetailsText>Example narrative</DetailsText>
</ctext:RootAugmentation>
I'd like it to go in as:
<ctext:DetailsText>Example narrative</ctext:DetailsText>
The prefix is just a way to not have to specify the namespace in every element that uses it, the namespace is most probably specified in the document the first time the prefix is used
To find the namespace URI, you can either look in the XML document and find the attribute that looks like:
<ctext:SomeElement xmlns:ctext="<namespace uri>">...
Once you have found it, you can use the CreateElement(string, string) overload to specify the namespaceUri.
doc.CreateElement("DetailsText", "<namespace uri for ctext>");
This will result in the element looking like:
<ctext:DetailsText />
You can specify the prefix in the CreateElement call i.e. "ctext:DetailsText" (Or by another overload), but this will automatically be looked up based on the namespaceUri you provide so in your case it's unnecessary. If you were to specify a different prefix, this will register the new prefix with the namespaceUri and add a new xmlns attribute on the element (which you don't want).

Get nodes from xml files

How to parse the xml file?
<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>link</loc>
<lastmod>2011-08-17T08:23:17+00:00</lastmod>
</sitemap>
<sitemap>
<loc>link</loc>
<lastmod>2011-08-18T08:23:17+00:00</lastmod>
</sitemap>
</sitemapindex>
I am new to XML, I tried this, but it seems to be not working :
XmlDocument xml = new XmlDocument(); //* create an xml document object.
xml.Load("sitemap.xml");
XmlNodeList xnList = xml.SelectNodes("/sitemapindex/sitemap");
foreach (XmlNode xn in xnList)
{
String loc= xn["loc"].InnerText;
String lastmod= xn["lastmod"].InnerText;
}
The problem is that the sitemapindex element defines a default namespace. You need to specify the namespace when you select the nodes, otherwise it will not find them. For instance:
XmlDocument xml = new XmlDocument();
xml.Load("sitemap.xml");
XmlNamespaceManager manager = new XmlNamespaceManager(xml.NameTable);
manager.AddNamespace("s", "http://www.sitemaps.org/schemas/sitemap/0.9");
XmlNodeList xnList = xml.SelectNodes("/s:sitemapindex/s:sitemap", manager);
Normally speaking, when using the XmlNameSpaceManager, you could leave the prefix as an empty string to specify that you want that namespace to be the default namespace. So you would think you'd be able to do something like this:
// WON'T WORK
XmlDocument xml = new XmlDocument();
xml.Load("sitemap.xml");
XmlNamespaceManager manager = new XmlNamespaceManager(xml.NameTable);
manager.AddNamespace("", "http://www.sitemaps.org/schemas/sitemap/0.9"); //Empty prefix
XmlNodeList xnList = xml.SelectNodes("/sitemapindex/sitemap", manager); //No prefixes in XPath
However, if you try that code, you'll find that it won't find any matching nodes. The reason for this is that in XPath 1.0 (which is what XmlDocument implements), when no namespace is provided, it always uses the null namespace, not the default namespace. So, it doesn't matter if you specify a default namespace in the XmlNamespaceManager, it's not going to be used by XPath, anyway. To quote the relevant paragraph from the Official XPath Specification:
A QName in the node test is expanded into an expanded-name using the
namespace declarations from the expression context. This is the same
way expansion is done for element type names in start and end-tags
except that the default namespace declared with xmlns is not used: if
the QName does not have a prefix, then the namespace URI is null (this
is the same way attribute names are expanded). It is an error if the
QName has a prefix for which there is no namespace declaration in the
expression context.
Therefore, when the elements you are reading belong to a namespace, you can't avoid putting the namespace prefix in your XPath statements. However, if you don't want to bother putting the namespace URI in your code, you can just use the XmlDocument object to return the URI of the root element, which in this case, is what you want. For instance:
XmlDocument xml = new XmlDocument();
xml.Load("sitemap.xml");
XmlNamespaceManager manager = new XmlNamespaceManager(xml.NameTable);
manager.AddNamespace("s", xml.DocumentElement.NamespaceURI); //Using xml's properties instead of hard-coded URI
XmlNodeList xnList = xml.SelectNodes("/s:sitemapindex/s:sitemap", manager);
Sitemap has 2 sub nodes "loc" and "lastmod". The nodes that you are accessing are "name" and "url". that is why you are not getting any result. Also in your XML file the last sitemap tag is not closed properly with a corresponding Kindly try xn["loc"].InnerText and see if you get the desired result.
I would definitely use LINQ to XML instead of the older XmlDocument based XML API. You can accomplish what you are looking to do using the following code. Notice, I changed the name of the element that I am trying to get the value of to 'loc' and 'lastmod', because this is what is in your sample XML ('name' and 'url' did not exist):
XElement element = XElement.Parse(XMLFILE);
IEnumerable<XElement> list = element.Elements("sitemap");
foreach (XElement e in list)
{
String LOC= e.Element("loc").Value;
String LASTMOD = e.Element("lastmod").Value;
}

Inserting "raw" XML string into a XElement

I'm trying to load a node (in string format) into a XElement.
Although this should be easy enough i'm finding some problems:
The node I'm trying to load contains namespace references in some sub-nodes
When I try to use XElement.Load() or Xelement.Parse() I get the expected not defined namespace error
I know the solution is to create a surrounding node with the namespace definitions and then load the whole thing, but I was wondering if there is a more elegant solution that doesn't involve string operations.
Here's my failed attempt :(
I have a collection of namespace attributes:
private readonly List<XAttribute> _namespaces;
This is already populated and contains all the necesary namespaces.
So, to embed my XML string into another node I was doing this:
var temp = new XElement("root", (from ns in _namespaces select ns), MyXMLString);
But as I expected as well, the content of MyXMLString gets escaped and becomes a text node.
The result I get is something like:
<root xmlns:mynamespace="http://mynamespace.com"><mynamespace:node>node text</node></root>
And the result I'm looking for is:
<root xmlns:mynamespace="http://mynamespace.com">
<mynamespace:node>node text</node>
</root>
Is there a neat way to do this?
Thanks in advance
Presumably your XML text is actually well formed (note the namespace qualifier on the closing tag):
var xml = "<mynamespace:node>node text</mynamespace:node>";
In which case you can use this to manually specify the namespaces:
var mngr = new XmlNamespaceManager( new NameTable() );
mngr.AddNamespace( "mynamespace", "urn:ignore" ); // or proper URL
var parserContext = new XmlParserContext(null, mngr, null, XmlSpace.None, null);
Now read and load:
var txtReader = new XmlTextReader( xml, XmlNodeType.Element, parserContext );
var ele = XElement.Load( txtReader );
Works as expected. And you don't need a wrapper 'root' node. Now this can be inserted into any as an XElement anywhere.

Get xml node value as string C#

I've been trying to pull the value of the XML node into a string. Here is what the XML looks like:
<currentvin value="1FTWW31R08EB18119" />
I can't seem to figure out how to grab that value. I didn't write this XML, by the way. So far I have tried several approaches, including the following:
public void xmlParse(string filePath)
{
XmlDocument xml = new XmlDocument();
xml.Load(filePath);
XmlNode currentVin = xml.SelectSingleNode("/currentvin");
string xmlVin = currentVin.Value;
Console.WriteLine(xmlVin);
}
Which doesn't work. I then tried:
public void xmlParse(string filePath)
{
XmlDocument xml = new XmlDocument();
xml.Load(filePath);
string xmlVin = xml.SelectSingleNode("/currentvin").Value;
Console.WriteLine(xmlVin);
}
But that doesn't work either. I am getting a null reference exception stating that Object reference not set to an instance of an object. Any ideas?
I think you're confusing the Value property of the XmlNode class, with an XML attribute named "value".
value is an attribute in your xml so either modify your xpath query to be
xml.SelectSingleNode("/currentvin/#value").Value
Or user the Attributes collection of the selected XmlNode.
You are looking for the value of the attribute "value" (that's a handful) not the value of the node itself - so you have to use the Attribute property:
string xmlVin = xml.SelectSingleNode("/currentvin").Attributes["value"].Value;
Or in the first version:
XmlNode currentVin = xml.SelectSingleNode("/currentvin");
string xmlVin = currentVin.Attributes["value"].Value;
If your entire XML contains only this node then it could be xml.DocumentElement.Attributes["value"].Value;

Getting single node from xml document c#

I'm trying to get channel element from this document.
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://purl.org/rss/1.0/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:syn="http://purl.org/rss/1.0/modules/syndication/"
xmlns:admin="http://webns.net/mvcb/"
xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
<channel rdf:about="http://developers.slashdot.org/">
<title>Slashdot: Developers</title>
<link>http://developers.slashdot.org/</link>
...
I think it's in the default namespace, which seems to be "http://purl.org/rss/1.0/" so I tried like this:
XmlNamespaceManager nsmsgr = new XmlNamespaceManager(rssDoc.NameTable);
nsmsgr.AddNamespace(String.Empty, "http://purl.org/rss/1.0/");
XmlNode root = rssDoc.DocumentElement;
XmlNode channel = rssDoc.SelectSingleNode("channel", nsmsgr);
I doesn't work. XmlNode channel stays null.
You can't add it as Empty.
http://msdn.microsoft.com/en-us/library/system.xml.xmlnamespacemanager.addnamespace.aspx
The prefix to associate with the
namespace being added. Use
String.Empty to add a default
namespace. Note If the
XmlNamespaceManager will be used for
resolving namespaces in an XML Path
Language (XPath) expression, a prefix
must be specified. If an XPath
expression does not include a prefix,
it is assumed that the namespace
Uniform Resource Identifier (URI) is
the empty namespace. For more
information about XPath expressions
and the XmlNamespaceManager, refer to
the XmlNode.SelectNodes and
XPathExpression.SetContext methods.XPathExpression.SetContext methods.
So just add the default prefix as "default", then use "/*/default:channel".
Working code:
var nsmsgr = new XmlNamespaceManager(rssDoc.NameTable);
nsmsgr.AddNamespace("default", "http://purl.org/rss/1.0/");
var root = rssDoc.DocumentElement;
var channel = rssDoc.SelectSingleNode("/*/default:channel", nsmsgr);
The above code works, but it's got a hardcoded URI and it uses a "cheat" to avoid dealing with the root node. Here's a cleaner, more general solution:
var nsmsgr = new XmlNamespaceManager(rssDoc.NameTable);
var root = rssDoc.DocumentElement;
nsmsgr.AddNamespace("default", root.GetAttribute("xmlns"));
nsmsgr.AddNamespace("rdf", root.GetAttribute("xmlns:rdf"));
var channel = rssDoc.SelectSingleNode("/rdf:RDF/default:channel", nsmsgr);
Just do:
XmlNode channel = rssDoc.SelectSingleNode(#"//channel");
XmlElement root = rssDoc.DocumentElement;
XmlNode channel = root.SelectSingleNode("/channel");
That will get you the channel node, you can then reference, Attributes, Value, InnerXML, FirstChild etc to pull the data from that node.
*edit: should have been XmlElement instead of Node

Categories