XML CDATA Encoding - c#

I am trying to build an XML document in C# with CDATA to hold the text inside an element. For example..
<email>
<![CDATA[test#test.com]]>
</email>
However, when I get the InnerXml property of the document, the CDATA has been reformatted so the InnerXml string looks like the below which fails.
<email>
<![CDATA[test#test.com]]>
</email>
How can I keep the original format when accessing the string of the XML?
Cheers

Don't use InnerText: use XmlDocument.CreateCDataSection:
using System;
using System.Xml;
public class Test
{
static void Main()
{
XmlDocument doc = new XmlDocument();
XmlElement root = doc.CreateElement("root");
XmlElement email = doc.CreateElement("email");
XmlNode cdata = doc.CreateCDataSection("test#test.com");
doc.AppendChild(root);
root.AppendChild(email);
email.AppendChild(cdata);
Console.WriteLine(doc.InnerXml);
}
}

With XmlDocument:
XmlDocument doc = new XmlDocument();
XmlElement email = (XmlElement)doc.AppendChild(doc.CreateElement("email"));
email.AppendChild(doc.CreateCDataSection("test#test.com"));
string xml = doc.OuterXml;
or with XElement:
XElement email = new XElement("email", new XCData("test#test.com"));
string xml = email.ToString();

See XmlDocument::CreateCDataSection Method for information and examples how to create CDATA nodes in an XML Document

Related

Adding a root node to Xml Document having a existing root node in C#

I have an xml document that may look like this
<Stuff>
<SomeStuff></SomeStuff>
</Stuff>
and I want to add a new root to this document, to make it look like this
<Root>
<Stuff>
<SomeStuff></SomeStuff>
</Stuff>
</Root>
This is what i tried
string inputXml = " <Stuff>
<SomeStuff></SomeStuff>
</Stuff>";
XmlDocument firstLossRootNode = new XmlDocument();
firstLossRootNode.LoadXml("<Root />");
var economyDocument = = XDocument.Parse(inputXml);
firstLossRootNode.DocumentElement.AppendChild(economyDocument.Document);
I was trying to Append it has a child but i was getting compile time error
Is there a way to do this in c# using Xdocument class.
In your example, you are using the XmlDocument class for your firstLossRootNode, but the XDocument class for your economyDocument. Is this by design? If not, the following code will do what you are trying to do:
using System;
using System.Xml.Linq;
string inputXml = "<Stuff><SomeStuff></SomeStuff></Stuff>";
XDocument firstLossRootNode = XDocument.Parse("<Root />");
XDocument economyDocument = XDocument.Parse(inputXml);
firstLossRootNode.Root.Add(economyDocument.FirstNode);

Working With Specific XML structure

I am trying to get some data from an XML document. I have no control over the schema. If it were up to me I would have chosen another schema. I am using C#'s XPATH library to get the data.
XML DOC
<Journals>
<name>Title of Journal</name>
<totalvolume>2</totalvolume>
<JournalList>
<Volume no="1">
<Journal>
<issue>01</issue>
<Title>Title 1</Title>
<date>1997-03-10</date>
<link>www.somelink.com</link>
</Journal>
<Journal>
<issue>02</issue>
<Title>Title 3</Title>
<date>1997-03-17</date>
<link>www.somelink.com</link>
</Journal>
</Volume>
<Volume no="2">
<Journal>
<issue>01</issue>
<Title>Title 1</Title>
<date>1999-01-01</date>
<link>www.somelink.com</link>
</Journal>
<Journal>
<issue>01</issue>
<Title>Title 2</Title>
<date>1999-01-08</date>
<link>www.somelink.com</link>
</Journal>
</Volume>
</JournalList>
</Journals>
I am trying to get all the data in the Volume 2 node. Here is what I tried so far:
C# Code:
protected void loadXML(string url)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(url);
string strQuery = "Volume[#no='2']";
XmlElement nodeList = xmlDoc.DocumentElement;
XmlNodeList JournalList = nodeList.SelectNodes(strQuery);
foreach (XmlElement Journal in JournalList)
{
XmlElement temp = Journal;
}
}
It seems there are no nodes in JournalList. Anyone? Thanks in advance/
Your code is looking for "Volume" nodes directly under the "Journals" node
Change this:
string strQuery = "Volume[#no='2']";
To this, in order to look for "Volume" nodes under the "JournalList" node:
string strQuery = "JournalList/Volume[#no='2']";
Also, there's a couple typos in your XML:
</Volume no="2"> -> <Volume no="2"> // no open tag found
</Journal> -> </Journals> // expecting end tag </Journals>
From your comment below:
how would I go about access each journal? for example. I want irrate through each "journal" and get the title of the journal?
In order to do that, you could modify your code slightly:
var nodeList = xmlDoc.DocumentElement;
var volume = nodeList.SelectSingleNode(strQuery);
foreach (XmlElement journal in volume.SelectNodes("Journal"))
{
var title = journal.GetElementsByTagName("Title")[0].InnerText;
}
Also you can use Linq to XML:
using System.Xml.Linq;
//...
string path="Path of your xml file"
XDocument doc = XDocument.Load(path);
var volume2= doc.Descendants("Volume").FirstOrDefault(e => e.Attribute("no").Value == "2");

Cannot select an XML node with XML namespace using SelectSingleNode method

I have the following XML
<?xml version="1.0" encoding="UTF-8"?>
<form:Documents xmlns:form="http://www.example.com/file.xsd" xmlns:addData="http://www.example.com/file2.xsd">
<_colored:_colored addData:DocumentState="Correct" xmlns:_colored="http://www.example.com/colored.xsd">
<_colored>
<_Field1>PB8996MT</_Field1>
</_colored>
</_colored:_colored>
</form:Documents>
I try to get the inner text of the _Field1 tag by writing the following C# code:
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(filePath);
string fieldValue = xmlDocument.SelectSingleNode("/form:Documents/_colored:_colored/_colored/_Field1").InnerText;
And when I run the application I get the following exception:
Unhandled Exception: System.Xml.XPath.XPathException: Namespace Manager or XsltContext needed.
This query has a prefix, variable, or user-defined function.
You should declare the namespace prefix using an XmlNamespaceManager before you can use it in XPath expressions.
XmlDocument doc = new XmlDocument ();
doc.Load("/Users/buttercup/Projects/23564466/kram.xml");
XmlNamespaceManager nmspc = new XmlNamespaceManager(doc.NameTable);
nmspc.AddNamespace("form", "http://www.example.com/file.xsd");
nmspc.AddNamespace("addData", "http://www.example.com/file2.xsd");
nmspc.AddNamespace("_colored", "http://www.example.com/colored.xsd");
string fieldValue = doc.SelectSingleNode("/form:Documents/_colored:_colored/_colored/_Field1", nmspc).InnerText;
http://msdn.microsoft.com/en-us/library/system.xml.xmlnamespacemanager.aspx
LINQ to Xml can make things easier:
XDocument doc = XDocument.Load(filePath);
var value = doc.Descendants("_Field1").First().Value;

How to write CData in xml

i have an xml like :
<?xml version="1.0" encoding="UTF-8"?>
<entry>
<entry_id></entry_id>
<entry_status></entry_status>
</entry>
i am writing data in it like:
XmlNode xnode = xdoc.SelectSingleNode("entry/entry_status");
xnode.InnerText = "<![CDATA[ " + Convert.ToString(sqlReader["story_status"]) + " ]]>" ;
but its change "<" to "&lt" of CDATA.
Please tell me how to fill values in above xml as a CData format.
i know that we can create CDATA like :
XmlNode itemDescription = doc.CreateElement("description");
XmlCDataSection cdata = doc.CreateCDataSection("<P>hello world</P>");
itemDescription.AppendChild(cdata);
item.AppendChild(itemDescription);
but my process is to read node of xml and change its value not to append in it.
Thanks
As described here: msdn
// Create an XmlCDataSection from your document
var cdata = xdoc.CreateCDataSection(Convert.ToString(sqlReader["story_status"]));
// Append the cdata section to your node
xnode.AppendChild(cdata);
Do you really need it to be in CDATA, or do you just want to get the text in there in a way which won't require extra escaping in your code?
InnerText performs whatever escaping is required, so generally I'd just use
xnode.InnerText = Convert.ToString(sqlReader["story_status"]);
... but if you really want a CDATA node, you can create one yourself as per Nekresh's answer.
If you really need a CDATA section (see Jon's answer), you can achieve that like so:
XmlNode xnode = xdoc.SelectSingleNode("entry/entry_status");
XmlCDataSection cdata = xdoc.CreateCDataSection(Convert.ToString(sqlReader["story_status"]));
xnode.InnerXml = cdata.OuterXml;
This will replace the contents of xnode, not append to it.
Use Node.InnerXml, not Node.InnerText. Node.InnerText is automatically replacing special values. Note that if you specify with CDATA in InnerXml, then Node.InnerText is text in CDATA.
Example:
public class Test
{
public static int Main(string[] args)
{
const string xmlTxt = #"<?xml version=""1.0"" encoding=""UTF-8""?>
<entry>
<entry_id></entry_id>
<entry_status></entry_status>
</entry>";
TextReader treader = new StringReader(xmlTxt);
XmlReader xreader = XmlReader.Create(treader);
XmlDocument xdoc = new XmlDocument();
xdoc.Load(xreader);
XmlNode xnode = xdoc.SelectSingleNode("entry/entry_status");
//xnode.InnerText = "<![CDATA[something]]>";
xnode.InnerXml = "<![CDATA[something]]>";
Console.WriteLine("inner text is: " + xnode.InnerText);
xdoc.Save(Console.Out); Console.WriteLine();
return 0;
}
}
Program's output:
inner text is: something
<?xml version="1.0" encoding="ibm852"?>
<entry>
<entry_id>
</entry_id>
<entry_status><![CDATA[something]]></entry_status>
</entry>
XmlNode childNode = node.ChildNodes[0];
if (childNode is XmlCDataSection)
{
XmlCDataSection cdataSection = childNode as XmlCDataSection;
cdataSection.Value = newValue;
}
You can use writer.WriteCData(value);
where writer is XmlWriter object.

How to add attributes to xml using XmlDocument in c# .net CF 3.5

I need to create an attribute "abc" with the prefix "xx" for an element "aaa". The following code adds the prefix but it also adds the namespaceUri to the element.
Required Output:
<mybody>
<aaa xx:abc="ddd"/>
<mybody/>
My Code:
XmlNode node = doc.SelectSingleNode("//mybody");
XmlElement ele = doc.CreateElement("aaa");
XmlAttribute newAttribute = doc.CreateAttribute("xx","abc",namespace);
newAttribute.Value = "ddd";
ele.Attributes.Append(newAttribute);
node.InsertBefore(ele, node.LastChild);
The above code generates :
<mybody>
<aaa xx:abc="ddd" xmlns:xx="http://www.w3.org/1999/XSL/Transform"/>
<mybody/>
Desired output is
<mybody>
<aaa xx:abc="ddd"/>
<mybody/>
And the declaration of the "xx" attribute should be done in the root node like :
<ns:somexml xx:xsi="http://www.w3.org/1999/XSL/Transform" xmlns:ns="http://x.y.z.com/Protocol/v1.0">
How can if get the output in the deisred format? If the xml is not in this desired format then it cannot be processed anymore..
Can anyone help?
Thanks,
Vicky
I believe it's just a matter of setting the relevant attribute directly on the root node. Here's a sample program:
using System;
using System.Globalization;
using System.Xml;
class Test
{
static void Main()
{
XmlDocument doc = new XmlDocument();
XmlElement root = doc.CreateElement("root");
string ns = "http://sample/namespace";
XmlAttribute nsAttribute = doc.CreateAttribute("xmlns", "xx",
"http://www.w3.org/2000/xmlns/");
nsAttribute.Value = ns;
root.Attributes.Append(nsAttribute);
doc.AppendChild(root);
XmlElement child = doc.CreateElement("child");
root.AppendChild(child);
XmlAttribute newAttribute = doc.CreateAttribute("xx","abc", ns);
newAttribute.Value = "ddd";
child.Attributes.Append(newAttribute);
doc.Save(Console.Out);
}
}
Output:
<?xml version="1.0" encoding="ibm850"?>
<root xmlns:xx="http://sample/namespace">
<child xx:abc="ddd" />
</root>

Categories