Writing Escape Characters in Plain Text with XML - c#

I'm having an issue parsing some XML with C#. To give an example, I'm taking some XML that contains the following tag:
<Message>Hello, my name is
Mr. Rogers</Message>
And parsing it with the following C# code:
var xmlData = XDocument.Load(filePath);
The problem that I'm having is that the above XML is being parsed as:
<Message>Hello, my name is
Mr. Rogers</Message>
when it needs to be parsed as:
<Message>Hello, my name is
Mr. Rogers</Message>
Is it possible to just have it parsed as the latter example in C#?

The only way is to do pre- and post-processing.
public XDocument LoadXDocument(string xmlString)
{
const string replacer = "|||==|||";
const string replacement = "
";
xmlString = xmlString.Replace(replacement, replacer);
XDocument doc;
using (var reader = new StringReader(xmlString))
{
doc = XDocument.Load(reader);
}
foreach (var element in doc.Elements())
{
if (element.Value.Contains(replacer))
{
element.SetValue(element.Value.Replace(replacer, replacement));
}
}
return doc;
}

Related

Formatting string in XML format and remove invalid attribute characters

I've a string say "<Node a="<b>">". I need to escape only the data and parse this string as a node in XMLWriter. Hence how to escape only the attribute value "<" and note the XML structure's "<".
using (var writer = XmlWriter.Create(Console.Out))
{
writer.WriteStartElement("Node");
writer.WriteAttributeString("a", "<b>");
}
Output <Node a="<b>" />
Firstly you should parse the string. Since this is not valid xml, you can't use an xml parser. You can try HtmlAgilityPack. Then you can write the values with xml writer.
string s = "<Node a=\"<b>\">";
var doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(s);
var node = doc.DocumentNode.FirstChild;
var attr = node.Attributes[0];
using (var writer = XmlWriter.Create(Console.Out))
{
writer.WriteStartElement(node.Name);
writer.WriteAttributeString(attr.Name, attr.Value);
}

Modifying element of Json string (in C#)

I'm trying to modify an attribute of an XML string using Json in C#. Currently I'm doing the following:
XmlDocument serializedFormXml = new XmlDocument();
serializedFormXml.LoadXml(mySerializedForm);
string formJsonString = JsonConvert.SerializeXmlNode(serializedFormXml, Newtonsoft.Json.Formatting.None, true);
JObject formJsonObj = JObject.Parse(formJsonString);
formJsonObj["#code"] = "myNewValue";
var xml = JsonConvert.DeserializeXmlNode(formJsonObj.ToString()).ToString();
When I do this I get get an exception on the last line:
Unable to cast object of type 'Newtonsoft.Json.Converters.XmlDocumentWrapper' to type 'Newtonsoft.Json.Converters.IXmlElement'
Any ideas what I'm doing wrong and how I can fix modify my form attribute "code"?
This is the XML I'm using:
<Form code="XYZ">
<Info>Data</Info>
.....
Thanks!
That's going to be way, way easier with Linq-to-XML:
var doc = XDocument.Parse(mySerializedForm);
doc.Root.SetAttributeValue(doc.Root.Name.Namespace + "code", "myNewValue");
var xml = doc.ToString();
This drops the XML declaration. If you need the XML declaration included, you can use the following extension method:
public static class XObjectExtensions
{
public static string ToXml(this XDocument xDoc)
{
using (var writer = new StringWriter())
{
xDoc.Save(writer);
return writer.ToString();
}
}
}
And then write:
var xml = doc.ToXml();
If specifically you need to make the encoding string say "UTF-8", use Utf8StringWriter from this answer.
Update
The reason you code fails is that you stripped the XML root element name away when you converted to json by passing true here:
string formJsonString = JsonConvert.SerializeXmlNode(serializedFormXml, Newtonsoft.Json.Formatting.None, true);
Thus you need to add it back when converting back:
var xml = JsonConvert.DeserializeXmlNode(formJsonObj.ToString(), serializedFormXml.DocumentElement.Name).ToString();

XmlSerializer - Present an array of items

I have an XML File that looks like this :
<ROOT><DOC> ... </DOC><DOC> ... </DOC><DOC> ... </DOC></ROOT>
I want to put all the DOC in an array.
How do I do that in C# (XmlSerializer) ?
In essence, you need a string that contains your XML, a StringReader to read the string, an XMLReader to read the feed from the StringReader and an XDocument to store the feed from the XMLReader. This can be done in a single line of code, like this:
XDocument xDoc = XDocument.Load (XmlReader.Create (new StringReader (xmlString)));
The xmlString is the path (and name) of the file you're reading. You should use a List to store the data you'll get (unless it's a set number, then you can just use a string[]).
List<string> docList = new List<string>();
Then it's a matter of using a foreach loop to go through the XML elements and adding them to your list:
foreach (var element in xDoc.Descendants("ROOT"))
{
string doc = element.Element ("DOC").Value;
docList.Add (doc);
}
to make it an array, use:
docList.ToArray();
I hope this helps! Good luck.
Maybe it depends on the framework version. I have .net v4 and would use the following class with XmlSerializer.
Thanks to #Reniuz for the hint of the error. Here is a full working example:
public class Document
{
[XmlAttribute]
public string Value { get; set; }
}
[XmlRoot("ROOT")]
public class Root
{
[XmlElement("DOC")]
public List<Document> Documents { get; set; }
}
Using this code to load:
string data = "<ROOT><DOC Value=\"adhfjasdhf\"></DOC><DOC Value=\"asldfhalsdh\"></DOC></ROOT>";
XmlSerializer serializer = new XmlSerializer(typeof(Root));
using (StringReader sr = new StringReader(data))
{
Root root = serializer.Deserialize(sr) as Root;
}
Keep attantion that the tags are case sensitive.
This is the right answer, based on Magicbjorn answer :
First of all, i'm getting my string from a StreamReader.
using(StreamReader read = new StreamReader("FilePath.xml"))
{
XDocument xDoc = XDocument.Load(XmlReader.Create(read));
List<string> docList = new List<string>();
var root = xDoc.Element("ROOT");
foreach (var element in root.Elements("DOC"))
{
string s = element.Value;
docList.Add(s);
}
}

How do I retrieve all data from an XML file?

I used this code for retrieving specific value from the XML file.Now i want to retrieve all the data which are present in the XML file .Can anybody help me to find out the solution?
StorageFile xmlFile = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync("Content1.xml");
XmlDocument xmlDoc;
xmlDoc = await XmlDocument.LoadFromFileAsync(xmlFile);
System.Xml.Linq.XDocument duc = System.Xml.Linq.XDocument.Parse(xmlDoc.GetXml());
var query=
from Date in duc.Root.Elements("Serial")
where Date.Attribute("No").Value=="1"
from Current in Date.Elements("Current")
select new {
NarratedBy=Current.Attribute("NarratedBy").Value,
value=Current.Attribute("Date").Value
};
foreach(var Date in query) {
System.Diagnostics.Debug.WriteLine("{0}\t{1}", Date.NarratedBy, Date.value);
}
You already have whole XML document loaded into duc variable.
That line is responsible for that:
System.Xml.Linq.XDocument duc = System.Xml.Linq.XDocument.Parse(xmlDoc.GetXml());
then you can just retrieve your XDocument details for example into a string variable with an XDocument extension ToString()
You have all data already:
xmlDoc = await XmlDocument.LoadFromFileAsync(xmlFile); // data loadded
System.Xml.Linq.XDocument duc = System.Xml.Linq.XDocument.Parse(xmlDoc.GetXml()); // data parsed
===================
Here is a sample code how you may do it. It is fully functional (using local string xml instead of your file) so you may run it. I added only three attributes but you may add as many as you want.
class Program {
static void Main(string[] args) {
// this is a sample string. Use your file instead
string s = "<catalog>" +
"<book id=\"bk101\" author=\"Gambardella, Matthew\" title=\"XML Developer's Guide\" genre=\"Computer\"/>" +
"<book id=\"bk102\" author=\"Ralls, Kim\" title=\"Midnight Rain\" genre=\"Fantasy\"/>" +
"</catalog>";
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(s); // here we load data
// here we get attributes. I have three, you will add three more. Also you may want to use string array instead of variables
foreach (XmlNode task in xdoc.DocumentElement.ChildNodes)
{
string author = task.Attributes["author"].InnerText;
string title = task.Attributes["title"].InnerText;
string genre = task.Attributes["genre"].InnerText;
}
}
}

XML parser, multiple roots

This is part of the input string, i can't modify it, it will always come in this way(via shared memory), but i can modify after i have put it into a string of course:
<sys><id>SCPUCLK</id><label>CPU Clock</label><value>2930</value></sys><sys><id>SCPUMUL</id><label>CPU Multiplier</label><value>11.0</value></sys><sys><id>SCPUFSB</id><label>CPU FSB</label><value>266</value></sys>
i've read it with both:
String.Concat(
XElement.Parse(encoding.GetString(bytes))
.Descendants("value")
.Select(v => v.Value));
and:
XmlDocument document = new XmlDocument();
document.LoadXml(encoding.GetString(bytes));
XmlNode node = document.DocumentElement.SelectSingleNode("//value");
Console.WriteLine("node = " + node);
but they both have an error when run; that the input has multiple roots(There are multiple root elements quote), i don't want to have to split the string.
Is their any way to read the string take the value between <value> and </value> without spiting the string into multiple inputs?
That's not a well-formed XML document, so most XML tools won't be able to process it.
An exception is the XmlReader. Look up XmlReaderSettings.ConformanceLevel in MSDN. If you set it to ConformanceLevel.Fragment, you can create an XmlReader with those settings and use it to read elements from a stream that has no top-level element.
You have to write code that uses XmlReader.Read() to do this - you can't just feed it to an XmlDocument (which does require that there be a single top-level element).
e.g.,
var readerSettings = new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment };
using (var reader = XmlReader.Create(stream, readerSettings))
{
while (reader.Read())
{
using (var fragmentReader = reader.ReadSubtree())
{
if (fragmentReader.Read())
{
var fragment = XNode.ReadFrom(fragmentReader) as XElement;
// do something with fragment
}
}
}
}
XML elements must have ONE root element, with whatever child structure you want.
Your xml string looks like:
<sys>
...
</sys>
<sys>
...
</sys>
The valid version would be:
<someRootElement>
<sys>
...
</sys>
<sys>
...
</sys>
</someElement>
Try:
XmlDocument document = new XmlDocument();
document.LoadXml("<root>"+encoding.GetString(bytes)+"</root>");
XmlNode node = document.DocumentElement.SelectSingleNode("//value");
Console.WriteLine("node = " + node);
This solution parses successfully all node types, including text nodes:
var settings = new XmlReaderSettings{ConformanceLevel = ConformanceLevel.Fragment};
var reader = XmlReader.Create(stream, settings);
while(reader.Read())
{
while(reader.NodeType != XmlNodeType.None)
{
if(reader.NodeType == XmlNodeType.XmlDeclaration)
{
reader.Skip();
continue;
}
XNode node = XNode.ReadFrom(reader);
}
}
Skips the XML declaration because it isn't a node.

Categories

Resources