Xmlwriter to Write to a String Instead of to a File

XmlWriter to Write to a String Instead of to a File

You need to create a StringWriter, and pass that to the XmlWriter.

The string overload of the XmlWriter.Create is for a filename.

E.g.

using (var sw = new StringWriter()) {
using (var xw = XmlWriter.Create(sw)) {
// Build Xml with xw.

}
return sw.ToString();
}

XML Writer stored results to string

Just use overloaded method XmlWriter.Create(StringBuilder output) to create xml string. In this case all output will be written to StringBuilder instead of file:

StringBuilder builder = new StringBuilder();
XmlWriter writer = XmlWriter.Create(builder);
//... build xml here

string xml = builder.ToString();

Also you can write xml to MemoryStream with XmlWriter.Create(Stream output).

Stream stream = new MemoryStream();
XmlWriter writer = XmlWriter.Create(stream);
// ... build xml here

stream.Position = 0;
string xml = new StreamReader(stream).ReadToEnd();

UPDATE

Extension method below will generate your xml string. By default it uses first column as element names, but you can pass any column index for column with meta data. Also I use table name to generate "Employees" tag, so provide name when you create data table DataTable dt = new DataTable("Employees");.

public static string ToXml(this DataTable table, int metaIndex = 0)
{
XDocument xdoc = new XDocument(
new XElement(table.TableName,
from column in table.Columns.Cast<DataColumn>()
where column != table.Columns[metaIndex]
select new XElement(column.ColumnName,
from row in table.AsEnumerable()
select new XElement(row.Field<string>(metaIndex), row[column])
)
)
);

return xdoc.ToString();
}

Usage is very simple:

string xml = dt.ToXml();

Output:

<Employees>
<Product_Name>
<hello1>product1</hello1>
<hello2>product2</hello2>
<hello3>product3</hello3>
<hello4>product4</hello4>
</Product_Name>
<product_Price>
<hello1>111</hello1>
<hello2>222</hello2>
<hello3>333</hello3>
<hello4>444</hello4>
</product_Price>
</Employees>

XmlWriter to both String and File

You could create a method like this:

private static void WriteXML(TextWriter writer)
{
using (var xw = XmlWriter.Create(writer))
{
// Build the xml
}
}

And then call it like:

using (StreamWriter sw = new StreamWriter(...))
WriteXML(sw);

to write a file or

string xml = String.Empty;
using (StringWriter sw = new StringWriter())
{
WriteXML(sw);
xml = sw.ToString();
}

To create the string.

You could even create helper methods:

private static void WriteXMLFile(string fileName)
{
using (StreamWriter sw = new StreamWriter(...))
WriteXML(sw);
}

private static string GetXML()
{
using (StringWriter sw = new StringWriter())
{
WriteXML(sw);
return sw.ToString();
}
}

Parsing XmlTextWriter object to String

The following function will extract the string from the System.Xml.XmlTextWriter objects you've created as Head and Body.

private string XmlTextWriterToString(XmlTextWriter writer)
{
// Ensure underlying stream is flushed.
writer.Flush();
// Reset position to beginning of stream.
writer.BaseStream.Position = 0;
using (var reader = new StreamReader(writer.BaseStream))
{
// Read and return content of stream as a single string
var result = reader.ReadToEnd();
return result;
}
}

Some caveats here are that the underlying System.IO.Stream object associated with the System.Xml.XmlTextWriter must support both 'read' and 'seek' operations (i.e., both Stream.CanRead and System.CanSeek properties must return true, respectively).

I've made the following edits to your original code:

  1. Replaced the Convert.ToString() calls with calls to this new function.
  2. Made an assumption that you're intending to write to the file specified by the filepath parameter to your SaveAsHTML() function, and not the hard-coded path.
  3. Wrapped the creation (and use, and disposal) of the System.Xml.XmlTextWriter in a using block (if you're not familiar, see What are the uses of “using” in C#?).

Following is your code with those changes.

public void SaveAsHTML(string filepath)
{
using (var html = new XmlTextWriter(filepath, System.Text.Encoding.UTF8))
{
html.WriteStartDocument();
html.WriteStartElement("html");
html.WriteRaw(XmlTextWriterToString(Head));
html.WriteRaw(XmlTextWriterToString(Body));
html.WriteEndElement();
html.WriteEndDocument();
html.Flush();
html.Close();
}
}

Another thing of which to be mindful is that, not knowing for sure from the code provided how they're being managed, the lifetimes of Head and Body are subject to the same exception-based resource leak potential that html was before wrapping it in the using block.

A final thought: the page for System.Xml.XmlTextWriter notes the following: Starting with the .NET Framework 2.0, we recommend that you create XmlWriter instances by using the XmlWriter.Create method and the XmlWriterSettings class to take advantage of new functionality.

How To Write A String(XML Node formatted without root) as nodes using XMLWriter in C#?

You must specify ConformanceLevel because your xml has no root element.

Also always should dispose all used resources.

using (XmlWriter writer = XmlWriter.Create(@"C:\\Test.XML"))
{
writer.WriteStartDocument();
writer.WriteStartElement("Test");

string scontent = "<A a=\"Hello\"></A><B b=\"Hello\"></B>";

var settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;

using (StringReader stringReader = new StringReader(scontent))
using (XmlReader xmlReader = XmlReader.Create(stringReader, settings))
{
writer.WriteNode(xmlReader, true);
}

writer.WriteEndElement();
}

In addition, you can use XmlWriterSettings to add indents.

Write to existing xml file without replacing it's contents (XmlWriter)

XML files are just sequential text files. They are not a database or a random-access file. There is no way to just write into the middle of them.



Related Topics



Leave a reply



Submit