Parsing Amazon s3 bucket listing with C# XmlDocument (Unity3d) - c#

Disclaimer: This issue is happening within a Unity application, but AFAIK, this is more of a C# issue than a Unity issue...
I am trying to use System.Xml.XmlDocument to parse an Amazon S3 bucket listing. Here is my bucket xml. I am using an example that I found in a C# Xml tutorial.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("http://rss.cnn.com/rss/edition_world.rss");
XmlNode titleNode = xmlDoc.SelectSingleNode("//rss/channel/title");
if(titleNode != null)
Debug.Log(titleNode.InnerText);
This works fine for that particular XML file, but when I put my stuff in there:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("https://s3.amazonaws.com/themall/");
Debug.Log ( xmlDoc.InnerXml );
XmlNode nameNode = xmlDoc.SelectSingleNode("//Name");
if(nameNode != null)
Debug.Log(nameNode.InnerText);
I get the raw XML in the console, so I know it is being downloaded successfully, but even the simplest XPath produces no results!
My only theory is that perhaps it has something to do with the default namespace in my XML? Do I need to tell XmlDocument about that somehow? Here is my root tag:
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
I have tried creating an XmlNamespaceManager and using it with all of my calls to "SelectSingleNode", but that doesn't seem to work either.
XPathNavigator nav = xmlDoc.CreateNavigator();
XmlNamespaceManager ns = new XmlNamespaceManager(nav.NameTable);
ns.AddNamespace(System.String.Empty, "http://s3.amazonaws.com/doc/2006-03-01/");
What am I doing wrong?
Thanks!

When you add the namespace to the namespace manager you need to give it a non-empty prefix. According to MSDN:
If the XmlNamespaceManager will be used for resolving namespaces in an XML Path Language (XPath) expression, a prefix must be specified.
Blockquote
The prefix must then be used in your XPath select statement. Here is the code I used and the output was "themall" as expected:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("http://s3.amazonaws.com/themall/");
XmlNamespaceManager namespaceManager =
new XmlNamespaceManager(xmlDoc.NameTable);
namespaceManager.AddNamespace("ns",
"http://s3.amazonaws.com/doc/2006-03-01/");
XmlNode titleNode =
xmlDoc.SelectSingleNode("//ns:Name", namespaceManager);
if (titleNode != null)
Console.WriteLine(titleNode.InnerText);

Related

How to copy node with all its children from an XML document to another one?

I have some C# code to open an XML document and to append the XML element to the selected node. However, I need to get copy of a bunch of nodes from one XML document to include them in another XML document.
How can I do this?
my C# code
XmlDocument Formal_TemplateField = new XmlDocument();
XmlDocument BuildMyGridView = new XmlDocument();
Formal_TemplateField.Load(Server.MapPath("~/Formal_TemplateField.xml"));
BuildMyGridView.Load(Server.MapPath("~/BuildMyGridView.xml"));
XmlElement controls = (XmlElement)Formal_TemplateField.SelectSingleNode("controls");
XmlElement Columns = BuildMyGridView.GetElementById("Columns");
Columns.AppendChild(controls); //<--- error here
BuildMyGridView.Save(Server.MapPath("~/BuildMyGridView.xml"));
This code gives me an error (System.NullReferenceException: 'Object reference not set to an instance of an object.')!
What is wrong?
I found the solution and the code will be just like this.
C#
XmlDocument Formal_TemplateField = new XmlDocument();
XmlDocument BuildMyGridView = new XmlDocument();
Formal_TemplateField.Load(Server.MapPath("~/Formal_TemplateField.xml"));
BuildMyGridView.Load(Server.MapPath("~/BuildMyGridView.xml"));
XmlNode NEW_NOOD = BuildMyGridView.ImportNode(Formal_TemplateField.DocumentElement["controls"], true);
BuildMyGridView.DocumentElement.GetElementsByTagName("Columns")[0].AppendChild(NEW_NOOD);
BuildMyGridView.Save(Server.MapPath("~/BuildMyGridView.xml"));

Using XDocument to read the root element from XML using C# is not showing the root element

I am new to C# programming and trying to update the XML file using C#. Here when I am trying to get the root element using XDocument it is showing the complete script in the file.
Below is my code explanation:
I am having the below function and it is reading the file path from the command line arguments.
private XDocument doc;
public void Update(string filepath)
{
string filename = Path.GetFileName(filepath);
doc = xDocument.Load(filepath);
XElement rootelement = doc.Root;
}
Into the filepath variable, we are taking the path "E:\BuilderTest\COMMON.wxs"
Then we are loading the file using XDocument.
But when we are trying to get the rootelement from the file, it is not showing the root element. Instead, it is showing the complete data in the file.
But when I am using XmlDocument() instead of XDocument() I am able to see only the root element.
Below is the code using XmlDocument():
private XmlDocument doc;
public void Update(string filepath)
{
string filename = Path.GetFileName(filepath);
doc = new XmlDocument();
doc.Load(filepath);
XmlElement rootelement = doc.DocumentElement;
}
Please help me by providing your valuable inputs on this.
XDocument and XmlDocument are different class structure to follow as per requirement.
XDocument will work like below
XDocument doc;
doc = XDocument.Load(filepath);
XElement root = doc.Root;
Root, Descendants, Elements are the operations provided in XDocument. For every node its gives XElement
In your case you should use doc.Root to find the element, then use .Value to get its value
XElement comes with System.Xml.Linq. It is derived from XNode.
It gives you serialized information of every node one by one.
On the other hand XMLDocument will work like below
XmlDocument doc;
doc = new XmlDocument();
doc.Load(filepath);
XmlElement rootelement = doc.DocumentElement;
XmlElement comes with System.Xml. It is derived from XmlNode which is again derived from IEnumerable.
It gives you information in a Enumerable which you can easily parse.

Generate XML from C# Code

I have to generate specific XML data from code.
The XML needs to look like this
<this:declarationIdentifier xmlns:this="demo.org.uk/demo/DeclarationGbIdentifier"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="demo.org.uk/demo/DeclarationGbIdentifier DeclarationGbIdentifier.xsd"
xmlns:nsIdentity="demo.org.uk/demo/DeclarationGbIdentityType">
<this:declarationIdentity>
<nsIdentity:declarationUcr>Hello World</nsIdentity:declarationUcr>
</this:declarationIdentity>
</this:declarationIdentifier>
I have dabbled with XmlSerializer and XDocument but cant get the output to match this exactly
Please help.
I believe this will produce your desired output. There possibly is a simpler way this is just off the cuff to get you started. With the prefixes that you are requiring I would look up XmlDocument and adding namespaces to it to have a better understanding of what the code below is doing. Also what I would do is attempt to acquire the XSD schema file and use the XSD.exe to build a .cs file and then you can move forward with the XmlSerializer. If you move forward with the code below i highly suggest moving off your namespaceuri's into some soft of settings file so you can easily modify them in the event they change.
XmlDocument doc = new XmlDocument();
XmlElement root = doc.CreateElement("this", "declarationIdentifier", "demo.org.uk/demo/DeclarationGbIdentifier");
root.SetAttribute("xmlns:this", "demo.org.uk/demo/DeclarationGbIdentifier");
root.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
//Just setting an Attribute of xsi:schemaLocation it would always drop the xsi prefix in the xml so this is different to accomodate that
XmlAttribute schemaAtt = doc.CreateAttribute("xsi", "schemaLocation", "http://www.w3.org/2001/XMLSchema-instance");
schemaAtt.Value = "demo.org.uk/demo/DeclarationGbIdentifier DeclarationGbIdentifier.xsd";
root.Attributes.Append(schemaAtt);
root.SetAttribute("xmlns:nsIdentity", "demo.org.uk/demo/DeclarationGbIdentityType");
doc.AppendChild(root);
XmlElement declarationIdentity = doc.CreateElement("this", "declarationIdentity", "demo.org.uk/demo/DeclarationGbIdentifier");
XmlElement declarationUcr = doc.CreateElement("nsIdentity","declarationUcr","demo.org.uk/demo/DeclarationGbIdentityType");
declarationUcr.InnerText = "Hello World";
declarationIdentity.AppendChild(declarationUcr);
doc.DocumentElement.AppendChild(declarationIdentity);
To output this as a string or dump it off to a file you can use the following operations, I output to a file as well as output to the console in my test app.
using (var stringWriter = new StringWriter())
using (StreamWriter writer = new StreamWriter(#"C:\<Path to File>\testing.xml"))
using (var xmlTextWriter = XmlWriter.Create(stringWriter))
{
doc.WriteTo(xmlTextWriter);
xmlTextWriter.Flush();
writer.Write(stringWriter.GetStringBuilder().ToString());
Console.WriteLine(stringWriter.GetStringBuilder().ToString());
}

How to read an XML document in C# with a namespace that has no associated prefix

I am trying to read OSIS formatted documents. I have cut the document down to a simple fragment:
<?xml version="1.0" encoding="utf-8"?>
<osis xmlns="http://www.bibletechnologies.net/2003/OSIS/namespace">
<osisText osisRefWork="Bible" osisIDWork="kjv" xml:lang="en">
</osisText>
</osis>
I try to read it with this sample code from the MSDN documentation:
XPathDocument document = new XPathDocument("osis.xml");
XPathNavigator navigator = document.CreateNavigator();
XPathNodeIterator nodes = navigator.Select("/osis/osisText");
while (nodes.MoveNext())
{
Console.WriteLine(nodes.Current.Name);
}
The problem is that the selection contains no nodes and throws no exception. Since the code discards the root tag, I can't read the document. If I remove the xmlns="http://www.bibletechnologies.net/2003/OSIS/namespace" from the root osis tag, it works just fine. The offensive URL returns a 404 code, but otherwise I see nothing wrong with this XML. Can someone explain why this code won't read the document? What options do I have besides hand editing every document before trying to load it?
Your XPath expression is missing a namespace prefix.
The element that you're trying to select has a namespace URI of http://www.bibletechnologies.net/2003/OSIS/namespace, and XPath will not match these nodes using paths with an empty namespace URI.
I tested this revision in .NET 2.0 and it found the node as expected.
XPathDocument document = new XPathDocument("osis.xml");
XPathNavigator navigator = document.CreateNavigator();
XmlNamespaceManager xmlns = new XmlNamespaceManager(navigator.NameTable);
xmlns.AddNamespace("osis", "http://www.bibletechnologies.net/2003/OSIS/namespace");
XPathNodeIterator nodes = navigator.Select("/osis:osis/osis:osisText", xmlns);
You can read the file to a string, replace the namespace in memory, and then load it using a string stream:
string s;
using(var reader = File.OpenText("osis.xml"))
{
s = reader.ReadToEnd();
}
s = s.Replace("xmlns=\"http://www.bibletechnologies.net/2003/OSIS/namespace\"", "");
Stream stream = new MemoryStream(Encoding.ASCII.GetBytes(s));
XPathDocument document = new XPathDocument("stream");
// Rest of the code

Recreate the same XML document if the original XML document is deleted

I developed a sample application to create an XML document, and I created and saved the XML documented. The application is still running but I delete that XML document and I am now trying to create a new XML using the same application. I got an error of
this document already has 'DocumentElement' node
if (File.Exists(AppPath) == false)
{
root = doc.CreateElement("LicenseDetails");
rootnode = doc.CreateElement("License");
Login = doc.CreateElement("Login_Name");
Login.InnerText = "KSC";
rootnode.AppendChild(Login);
root.AppendChild(rootnode);
doc.AppendChild(root);
doc.Save(AppPath);
}
I can easily append the node in existing XML document but what I want to do is: if my XML got deleted, application has to create a new XML with same tags.
The issue is even if you delete the XML, the doc element you are using is the same one as before. So when you try to add the root element to the doc element exception is thrown. A possible solution is as as follows:
eg:
XmlDocument doc;
XmlElement root;
XmlElement rootnode;
XmlElement Login;
if (File.Exists(#"C:\Test.xml") == false)
{
doc = new XmlDocument();
root = doc.CreateElement("LicenseDetails");
rootnode = doc.CreateElement("License");
Login = doc.CreateElement("Login_Name");
Login.InnerText = "KSC";
rootnode.AppendChild(Login);
root.AppendChild(rootnode);
doc.AppendChild(root);
doc.Save(#"C:\Test.xml");
}
So when you get to this block again it will execute without issues.
Use DocumentElement property - It return the root element of Xml document.
XmlDocument dom=new XmlDocument();
dom.Load("file.xml");
XmlElement ele1=dom.createElement("A");
XmlElement ele2=dom.createElement("B");
ele1.AppendChild(ele2);
dom.DocumentElement.AppendChild(ele1);
dom.Save("file.xml");

Categories

Resources