XDocument.ToString() drops XML Encoding Tag - c#

Is there any way to get the xml encoding in the toString() Function?
Example:
xml.Save("myfile.xml");
leads to
<?xml version="1.0" encoding="utf-8"?>
<Cooperations>
<Cooperation>
<CooperationId>xxx</CooperationId>
<CooperationName>Allianz Konzern</CooperationName>
<LogicalCustomers>
But
tb_output.Text = xml.toString();
leads to an output like this
<Cooperations>
<Cooperation>
<CooperationId>xxx</CooperationId>
<CooperationName>Allianz Konzern</CooperationName>
<LogicalCustomers>
...

Either explicitly write out the declaration, or use a StringWriter and call Save():
using System;
using System.IO;
using System.Text;
using System.Xml.Linq;
class Test
{
static void Main()
{
string xml = #"<?xml version='1.0' encoding='utf-8'?>
<Cooperations>
<Cooperation />
</Cooperations>";
XDocument doc = XDocument.Parse(xml);
StringBuilder builder = new StringBuilder();
using (TextWriter writer = new StringWriter(builder))
{
doc.Save(writer);
}
Console.WriteLine(builder);
}
}
You could easily add that as an extension method:
public static string ToStringWithDeclaration(this XDocument doc)
{
if (doc == null)
{
throw new ArgumentNullException("doc");
}
StringBuilder builder = new StringBuilder();
using (TextWriter writer = new StringWriter(builder))
{
doc.Save(writer);
}
return builder.ToString();
}
This has the advantage that it won't go bang if there isn't a declaration :)
Then you can use:
string x = doc.ToStringWithDeclaration();
Note that that will use utf-16 as the encoding, because that's the implicit encoding in StringWriter. You can influence that yourself though by creating a subclass of StringWriter, e.g. to always use UTF-8.

The Declaration property will contain the XML declaration. To get the contents plus declaration, you can do the following:
tb_output.Text = xml.Declaration.ToString() + xml.ToString()

use this:
output.Text = String.Concat(xml.Declaration.ToString() , xml.ToString())

I did like this
string distributorInfo = string.Empty;
XDocument distributors = new XDocument();
//below is important else distributors.Declaration.ToString() throws null exception
distributors.Declaration = new XDeclaration("1.0", "utf-8", "yes");
XElement rootElement = new XElement("Distributors");
XElement distributor = null;
XAttribute id = null;
distributor = new XElement("Distributor");
id = new XAttribute("Id", "12345678");
distributor.Add(id);
rootElement.Add(distributor);
distributor = new XElement("Distributor");
id = new XAttribute("Id", "22222222");
distributor.Add(id);
rootElement.Add(distributor);
distributors.Add(rootElement);
distributorInfo = String.Concat(distributors.Declaration.ToString(), distributors.ToString());
Please see below for what I get in distributorInfo
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Distributors>
<Distributor Id="12345678" />
<Distributor Id="22222222" />
<Distributor Id="11111111" />
</Distributors>

Similar to the other +1 answers, but a bit more detail about the declaration, and a slightly more accurate concatenation.
<xml /> declaration should be on its own line in a formatted XML, so I'm making sure we have the newline added.
NOTE: using Environment.Newline so it will produce the platform specific newline
// Parse xml declaration menthod
XDocument document1 =
XDocument.Parse(#"<?xml version=""1.0"" encoding=""iso-8859-1""?><rss version=""2.0""></rss>");
string result1 =
document1.Declaration.ToString() +
Environment.NewLine +
document1.ToString() ;
// Declare xml declaration method
XDocument document2 =
XDocument.Parse(#"<rss version=""2.0""></rss>");
document2.Declaration =
new XDeclaration("1.0", "iso-8859-1", null);
string result2 =
document2.Declaration.ToString() +
Environment.NewLine +
document2.ToString() ;
Both results produce:
<?xml version="1.0" encoding="iso-8859-1"?>
<rss version="2.0"></rss>

A few of these answers solve the poster's request, but seem overly complicated. Here's a simple extension method that avoids the need for a separate writer, handles a missing declaration and supports the standard ToString SaveOptions parameter.
public static string ToXmlString(this XDocument xdoc, SaveOptions options = SaveOptions.None)
{
var newLine = (options & SaveOptions.DisableFormatting) == SaveOptions.DisableFormatting ? "" : Environment.NewLine;
return xdoc.Declaration == null ? xdoc.ToString(options) : xdoc.Declaration + newLine + xdoc.ToString(options);
}
To use the extension, just replace xml.ToString() with xml.ToXmlString()

You can also use an XmlWriter and call the
Writer.WriteDocType()
method.

string uploadCode = "UploadCode";
string LabName = "LabName";
XElement root = new XElement("TestLabs");
foreach (var item in returnList)
{
root.Add(new XElement("TestLab",
new XElement(uploadCode, item.UploadCode),
new XElement(LabName, item.LabName)
)
);
}
XDocument returnXML = new XDocument(new XDeclaration("1.0", "UTF-8","yes"),
root);
string returnVal;
using (var sw = new MemoryStream())
{
using (var strw = new StreamWriter(sw, System.Text.UTF8Encoding.UTF8))
{
returnXML.Save(strw);
returnVal = System.Text.UTF8Encoding.UTF8.GetString(sw.ToArray());
}
}
// ReturnVal has the string with XML data with XML declaration tag

Extension method to get the Xml Declaration included, using string interpolation here and chose to add a new line after xml declaration as this is the standard I guess.
public static class XDocumentExtensions {
public static string ToStringIncludeXmlDeclaration(this XDocument doc){
return $"({((doc.Declaration != null ? doc.Declaration.ToString() +
Environment.NewLine : string.Empty) + doc.ToString())}";
}
}
}
Usage:
tb_output.Text = xml.ToStringIncludeXmlDeclaration();

Related

getting "null" value for xml

in this xml
<Roots>
<Root Name="cab">element_list</Root>
</Roots>
I want to get the value of attribute Name which is cab and element_list
I have this code
XmlDocument doc = new XmlDocument();
doc.LoadXml("<Root Name=\"cab\">element_list</Root>");
XmlElement root = doc.DocumentElement;
var values = doc.Descendants("Roots").Select(x => new { Name = (string)x.Attribute("Name"), List = (string)x }).ToList();
What I get when I run the debugger is
values> Name = "null", List = "element_list"
I am not understanding why I am getting a null value when I should be getting cab for the attribute Name
XDocument is much easier to work with compared to XmlDocument. Perhaps consider switching to it?
public static void ParseXml()
{
string str = "<Roots><Root Name=\"cab\">element_list</Root></Roots>";
using TextReader textReader = new StringReader(str);
XDocument doc = XDocument.Load(textReader);
var val = doc.Element("Roots").Element("Root").Attribute("Name").Value;
}

Simple C# Linq to Xml

I would like to be able to output the following format using C# Linq to Xml.
<Genres>
<Genre Value="Rock" />
<Genre Value="Metal" />
</Genres>
Consider the following function. I want to evaluate each of the parameters but only add the ones that are not empty strings.
private XmlElement createGenresXml(string str1 = "", string str2 = "Rock", string str3 = "Metal", string str4 = "")
{
'Return XmlElement should look like the Xml above.
}
Thanks! \m/ \m/
public XmlElement CreateGenresXml(string[] args)
{
var el = new XElement("Genres");
el.Add(args.Where(x => !string.IsNullOrWhiteSpace(x)).Select(arg => new XElement("Genre", new XAttribute("Value", arg))));
var doc = new XmlDocument();
using (var reader = el.CreateReader())
{
doc.Load(reader);
}
return doc.DocumentElement;
}
The conversion to XmlElement borrowed from here:

Convert Comma separated string to XML using C#

I want to convert the string to XML.
I have a string like below. It contains the Programming language names.
string lang = "java,php,c#,asp.net,spring,hibernate";
I want to convert this string to XML formal like below:
<Languages>
<lang Name="java"/>
<lang Name="php"/>
<lang Name="c#"/>
<lang Name="asp.net"/>
<lang Name="spring"/>
<lang Name="hibernate"/>
</Languages>
I want to store this XML data in a variable to store later in a database.
It can also be done using Linq-to-XML:
using System.Xml.Linq; // required namespace
XDocument xmlDoc = new XDocument();
XElement xElm = new XElement("Languages",
from l in lang.Split(',')
select new XElement("lang", new XAttribute("Name", l)
)
);
xmlDoc.Add(xElm);
string lang = "java,php,c#,asp.net,spring,hibernate";
string[] langs = lang.Split(',');
XmlDocument document = new XmlDocument();
XmlElement root = document.CreateElement("Languages");
document.AppendChild(root);
for (int i = 0; i < langs.Length; i++)
{
XmlElement langElement = document.CreateElement("lang");
XmlAttribute nameAttr = document.CreateAttribute("Name");
nameAttr.Value = langs[i];
langElement.Attributes.Append(nameAttr);
root.AppendChild(langElement);
}
document.WriteTo(new XmlTextWriter(Console.Out) {
Formatting = Formatting.Indented
});
A short version of what you have done, using Linq and the string manipulation functions
var vales = lang.Split(','); //Splits the CSV
var xmlBody = vales.Select(v => string.Format("<lang Name=\"{0}\"/>",v));
var xml = string.Join(string.Empty, xmlBody); //Potentially add a new line as a seperator
xml = string.Format("<Languages>{0}</Languages>", xml);
The other option is to convert your csv into a model that implements ISerialize and then use the xml serializer. That is more code and not necessarily bad. If you would like to see an example, feel free to ask and I will post an example.
This is working,
class Program
{
static void Main(string[] args)
{
string lang = "java,php,c#,asp.net,spring,hibernate";
StringBuilder sb = new StringBuilder();
sb.AppendFormat("<Languages>");
foreach (string s in lang.Split(','))
{
sb.AppendFormat("<lang Name=\"{0}\"/>", s);
}
sb.AppendFormat("</Languages>");
Console.WriteLine(sb.ToString());
Console.ReadLine();
}
}

Reading specific data from XML file in C#

I want to read specific data from an XML file.
This is what I have come up with so far:
When I run my program without the (if (reader.Name == ControlID)) line reader.Value returns the right value,but when I include the if clause,it returns null
public void GetValue(string ControlID)
{
XmlTextReader reader = new System.Xml.XmlTextReader("D:\\k.xml");
string contents = "";
while (reader.Read())
{
reader.MoveToContent();
if (reader.Name == ControlID)
contents = reader.Value;
}
}
Go through following code:
XmlDocument doc = new XmlDocument();
doc.Load(filename);
string xpath = "/Path/.../config"
foreach (XmlElement elm in doc.SelectNodes(xpath))
{
Console.WriteLine(elm.GetAttribute("id"), elm.GetAttribute("desc"));
}
Using XPathDocument (faster, smaller memory footprint, read-only, weird API):
XPathDocument doc = new XPathDocument(filename);
string xpath = "/PathMasks/Mask[#desc='Mask_X1']/config"
XPathNodeIterator iter = doc.CreateNavigator().Select(xpath);
while (iter.MoveNext())
{
Console.WriteLine(iter.Current.GetAttribute("id"), iter.Current.GetAttribute("desc'));
}
Can also refer this link:
http://support.microsoft.com/kb/307548
This might be helpful to you.
You can try the following code for example xPath query:
XmlDocument doc = new XmlDocument();
doc.Load("k.xml");
XmlNode absoluteNode;
/*
*<?xml version="1.0" encoding="UTF-8"?>
<ParentNode>
<InfoNode>
<ChildNodeProperty>0</ChildNodeProperty>
<ChildNodeProperty>Zero</ChildNodeProperty>
</InfoNode>
<InfoNode>
<ChildNodeProperty>1</ChildNodeProperty>
<ChildNodeProperty>One</ChildNodeProperty>
</InfoNode>
</ParentNode>
*/
int parser = 0
string nodeQuery = "//InfoNode//ChildNodeProperty[text()=" + parser + "]";
absoluteNode = doc.DocumentElement.SelectSingleNode(nodeQuery).ParentNode;
//return value is "Zero" as string
var nodeValue = absoluteNode.ChildNodes[1].InnerText;

How to use XmlSerializer to deserialize a simple collection into an instance of List<string>

I haven't been able to find a question related to my specific problem.
What I am trying to do is take a list of Xml nodes, and directly deserialize them to a List without having to create a class with attributes.
So the xml (myconfig.xml) would look something like this...
<collection>
<item>item1</item>
<item>item2</item>
<item>item3</item>
<item>etc...</item>
</collection>
In the end I would like a list of items as strings.
The code would look like this.
XmlSerializer serializer = new XmlSerializer( typeof( List<string> ) );
using (XmlReader reader = XmlReader.Create( "myconfig.xml" )
{
List<string> itemCollection = (List<string>)serializer.Deserialize( reader );
}
I'm not 100% confident that this is possible, but I'm guessing it should be. Any help would be greatly appreciated.
Are you married to the idea of using a serializer? If not, you can try Linq-to-XML. (.NET 3.5, C# 3 [and higher])
Based on your provided XML file format, this is the simple code.
// add 'using System.Xml.Linq' to your code file
string file = #"C:\Temp\myconfig.xml";
XDocument document = XDocument.Load(file);
List<string> list = (from item in document.Root.Elements("item")
select item.Value)
.ToList();
Ok, interestingly enough I may have found half the answer by serializing an existing List.
The result I got is as follows...
This following code:
List<string> things = new List<string> { "thing1", "thing2" };
XmlSerializer serializer = new XmlSerializer(typeof(List<string>), overrides);
using (TextWriter textWriter = new StreamWriter("things.xml"))
{
serializer.Serialize(textWriter, things);
}
Outputs a result of:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>thing1</string>
<string>thing2</string>
</ArrayOfString>
I can override the root node by passing an XmlAttributeOverrides instance to the second parameter of the XmlSerializer constructor. It is created like this:
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
XmlAttributes attributes = new XmlAttributes { XmlRoot = new XmlRootAttribute("collection") };
overrides.Add( typeof(List<string>), attributes );
This will change "ArrayOfString" to "collection". I still have not figured out how to control the name of the string element.
To customize List element names using XmlSerializer, you have to wrap the list.
[XmlRoot(Namespace="", ElementName="collection")]
public class ConfigWrapper
{
[XmlElement("item")]
public List<string> Items{ get; set;}
}
Usage:
var itemsList = new List<string>{"item1", "item2", "item3"};
var cfgIn = new ConfigWrapper{ Items = itemsList };
var xs = new XmlSerializer(typeof(ConfigWrapper));
string fileContent = null;
using (var sw = new StringWriter())
{
xs.Serialize(sw, cfgIn);
fileContent = sw.ToString();
Console.WriteLine (fileContent);
}
ConfigWrapper cfgOut = null;
using (var sr = new StringReader(fileContent))
{
cfgOut = xs.Deserialize(sr) as ConfigWrapper;
// cfgOut.Dump(); //view in LinqPad
if(cfgOut != null)
// yields 'item2'
Console.WriteLine (cfgOut.Items[1]);
}
Output:
// fileContent:
<?xml version="1.0" encoding="utf-16"?>
<collection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<item>item1</item>
<item>item2</item>
<item>item3</item>
</collection>
If you don't want to wrap the list, the DataContractSerializer will allow you to custom name the elements if you subclass it:
[CollectionDataContract(Name = "collection", ItemName = "item", Namespace = "")]
public class ConfigWrapper : List<string>
{
public ConfigWrapper() : base() { }
public ConfigWrapper(IEnumerable<string> items) : base(items) { }
public ConfigWrapper(int capacity) : base(capacity) { }
}
Usage And Output:
var cfgIn = new ConfigWrapper{ "item1", "item2", "item3" };
var ds = new DataContractSerializer(typeof(ConfigWrapper));
string fileContent = null;
using (var ms = new MemoryStream())
{
ds.WriteObject(ms, cfgIn);
fileContent = Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine (fileContent);
}
// yields: <collection xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><item>item1</item><item>item2</item><item>item3</item></collection>
ConfigWrapper cfgOut = null;
using (var sr = new StringReader(fileContent))
{
using(var xr = XmlReader.Create(sr))
{
cfgOut = ds.ReadObject(xr) as ConfigWrapper;
// cfgOut.Dump(); //view in LinqPad
if(cfgOut != null)
// yields 'item2'
Console.WriteLine (cfgOut[1]);
}
}

Categories

Resources