my code is outputting some weird character at the very start of my XSLT output XML and neither Visual Studio 2008 or notepad show it up. But it's definitely there because VS lets me delete it and will then auto-format the XML properly. How do I stop this? Here's my code:
// create the readers for the xml and xsl
XmlReader reader = XmlReader.Create(
new StringReader(LoadFileAsString(MapPath(xslPath)))
);
XmlReader input = XmlReader.Create(
new StringReader(LoadFileAsString(MapPath(xmlPath)))
);
// create the xsl transformer
XslCompiledTransform t = new XslCompiledTransform(true);
t.Load(reader);
// create the writer which will output the transformed xml
StringBuilder sb = new StringBuilder();
//XmlWriterSettings tt = new XmlWriterSettings();
//tt.Encoding = Encoding.Unicode;
XmlWriter results = XmlWriter.Create(new StringWriter(sb));//, tt);
// write the transformed xml out to a stringbuilder
t.Transform(input, null, results);
// return the transformed xml
WriteStringAsFile(MapPath(outputXmlPath), sb.ToString());
public static string LoadFileAsString(string fullpathtofile)
{
string a = null;
using (var sr = new StreamReader(fullpathtofile))
a = sr.ReadToEnd();
return a;
}
public static void WriteStringAsFile(string fullpathtofile, string content)
{
File.WriteAllText(fullpathtofile, content.Trim(), Encoding.Unicode);
}
That thing at the beginning of your XML output document is most likely a byte-order-mark or BOM, which indicates whether the bytes in your Unicode output are in big-endian or little-endian order.
This BOM might be useful for consumers of your XML document; however, in some cases it might lead to problems and then it is better not to create it.
You can specify whether a BOM is created using the Encoding specified via XmlWriterSettings:
XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
xmlWriterSettings.Encoding = new UTF8Encoding(false);
The code above will create your document using UTF8 encoding. This is most likely what you want to have unless your consuming system explicitly asks for UTF16/Unicode encoding or you are dealing with Asian character.
To create a UTF16/Unicode encoded document use UnicodeEncoding with the second parameter set to false:
XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
xmlWriterSettings.Encoding = new UnicodeEncoding(false, false);
Related
While working on csproj files as xml files (xmlDocument) somehow after saving, encoding changes from UTF-8 to ASCII. The only solution I figured out is to use StreamWriter with declared encoding. But this adds a header to file.
Questions:
1. Do you know any other solution to this problem?
2. Can I leave changed csproj?
StreamReader sr = new StreamReader(projectFilePath, Encoding.UTF8);
XmlDocument xmlCsproj = new XmlDocument();
xmlCsproj.Load(sr);
sr.Close();
// Working on XML nodes (replace references paths)
StreamWriter sw= new StreamWriter(projectFilePath, false, Encoding.UTF8);
xmlCsproj.Save(sw);
sw.Close();
This should work?
var writer = new XmlTextWriter(projectFilePath, Encoding.UTF8)
{
Formatting = Formatting.Indented
};
xmlCsproj.WriteContentTo(writer);
writer.Close();
First of all, UTF8 character values are identical to US-ASCII values in the range 0-127. There's no way to say if a csproj file was saved as US-ASCII or UTF8 unless the file contained non-English text, like non-English file paths. Is that what happened here? Even so, XmlDocument.Save should have used UTF8 by default.
You can control how an XmlDocument is written to a stream or file using an XmlWriter and XmlWriterSettings. In this case, you need to set the OmitXmlDeclaration :
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
var writer = XmlWriter.Create(projectFilePath, settings);
xmlCsproj.Save(sw);
sw.Close();
The default encoding is UTF8. To change it, you can set the XmlWriterSettings.Encoding to a different value
I've a class correctly defined and after serialize it to XML I'm getting no encoding.
How can I define encoding "ISO-8859-1"?
Here's a sample code
var xml = new XmlSerializer(typeof(Transacao));
var file = new FileStream(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "transacao.xml"),FileMode.OpenOrCreate);
xml.Serialize(file, transacao);
file.Close();
Here are the beginning of xml generated
<?xml version="1.0"?>
<requisicao-transacao xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<dados-ec>
<numero>1048664497</numero>
The following should work:
var xml = new XmlSerializer(typeof(Transacao));
var fname = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "transacao.xml");
var appendMode = false;
var encoding = Encoding.GetEncoding("ISO-8859-1");
using(StreamWriter sw = new StreamWriter(fname, appendMode, encoding))
{
xml.Serialize(sw, transacao);
}
If you don't mind me asking, why do you need ISO-8859-1 encoding in particular? You could probably use UTF-8 or UTF-16 (they're more commonly recognizable) and get away with it.
Create a StreamWriter with the desired encoding:
System.Text.Encoding code = *WhateverYouWant*
StreamWriter sw = new StreamWriter(file, code);
I would like to perform object serialization to only one branch in an existing XML file. While reading by using:
RiskConfiguration AnObject;
XmlSerializer Xml_Serializer = new XmlSerializer(typeof(RiskConfiguration));
XmlTextReader XmlReader = new XmlTextReader(#"d:\Projects\RiskService\WCFRiskService\Web.config");
XmlReader.ReadToDescendant("RiskConfiguration");
try
{
AnObject = (RiskConfiguration)Xml_Serializer.Deserialize(XmlReader);
AnObject.Databases.Database[0].name = "NewName";
}
finally
{
XmlReader.Close();
}
It is possible, I do not know how to edit the object again performed it can save the file without erasing other existing elements in an XML file. Can anyone help me?
I found a way to display the desired item serialization. How do I go now instead of the paste to the original element in XML?
StringWriter wr = new StringWriter();
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
settings.Encoding = System.Text.Encoding.Default;
using (XmlWriter writer = XmlWriter.Create(wr, settings))
{
XmlSerializerNamespaces emptyNamespace = new XmlSerializerNamespaces();
emptyNamespace.Add(String.Empty, String.Empty);
Xml_Serializer.Serialize(writer, AnObject, emptyNamespace);
MessageBox.Show(wr.ToString());
}
First of all, you should stop using new XmlTextReader(). That has been deprecated since .NET 2.0. Use XmlReader.Create() instead.
Second, XML is not a random-access medium. You can't move forward and backwards, writing into the middle of the file. It's a text-based file.
If you need to "modify" the file, then you'll need to write a new version of the file. You could read from the original file, up to the point where you need to deserialize, writing the nodes out to a new version of the file. You could then deserialize from the original file, modify the objects, and serialize out to the new version. You could then continue reading from the original and writing the nodes out to the new version.
The code below is causing the " Data at the root level is invalid. Line 1, position 1. "
I like to keep the code indent(linebreak) but keep having the problem as mentioned above. I could use the TextReader to load the xml but it will remove the indent which i don't like it. If you know how to fix problem please let me know. Thanks
public XmlDocument MYXML()
{
XmlWriterSettings wSettings = new XmlWriterSettings();
wSettings.Indent = false;
wSettings.OmitXmlDeclaration = false;
MemoryStream ms = new MemoryStream();
XmlWriter xw = XmlWriter.Create(ms, wSettings);// Write Declaration
xw.WriteStartDocument();
// Write the root node
xw.WriteStartElement("Library");
// Write the books and the book elements
xw.WriteStartElement("Book");
xw.WriteStartAttribute("BookType");
xw.WriteString("Hardback");
xw.WriteEndAttribute();
xw.WriteStartElement("Title");
xw.WriteString("Door Number Three");
xw.WriteEndElement();
xw.WriteStartElement("Author");
xw.WriteString("O'Leary, Patrick");
xw.WriteEndElement();
xw.WriteEndElement();
xw.WriteEndElement();
// Close the document
xw.WriteEndDocument();
// Flush the write
xw.Flush();
Byte[] buffer = new Byte[ms.Length];
buffer = ms.ToArray();
string xmlOutput = System.Text.Encoding.UTF8.GetString(buffer);
//The next 3 line works fine but it will remove the Indent from the XmlWriterSettings
//TextReader tr = new StreamReader(ms);
//ms.Seek(0, SeekOrigin.Begin);
//xmlOutput = tr.ReadToEnd() + "";
//Can't nload the xmlOutput from buffer
XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(xmlOutput);
return xmldoc;
}
The XmlWriter is writing a utf-8 byte-order mark to the stream. Encoding.UTF8.GetString doesn't account for this (since it's only supposed to occur in files) so the first character of the string becomes an invalid, unprintable character, which is what XmlDocument.LoadXml chokes on.
EDIT: Since you said you want to create an XmlDocument so you can reuse it, I recommend one of the following:
If using .Net 3.5 or newer, use XDocument which is much easier to use (I recommend this).
Create the XmlDocument directly by constructing nodes and adding them to the tree.
Create the XmlDocument directly from the writer by using XPathNavigator (XmlWriter writer = doc.CreateNavigator.AppendChild())
Note that you can't easily add insignificant whitespace to an XmlDocument. Using XDocument and writing it to the output using doc.Save(Response.Output) is by far the easiest option if you want to have nicely formatted output.
I have an XmlTextWriter writing to a file and an XmlWriter using that text writer. This text writer is set to output tab-indented XML:
XmlTextWriter xtw = new XmlTextWriter("foo.xml", Encoding.UTF8);
xtw.Formatting = Formatting.Indented;
xtw.IndentChar = '\t';
xtw.Indentation = 1;
XmlWriter xw = XmlWriter.Create(xtw);
Changed per Jeff's MSDN link:
XmlWriterSettings set = new XmlWriterSettings();
set.Indent = true;
set.IndentChars = "\t";
set.Encoding = Encoding.UTF8;
xw = XmlWriter.Create(f, set);
This does not change the end result.
Now I'm an arbitrary depth in my XmlWriter and I'm getting a string of XML from elsewhere (that I cannot control) that is a single-line, non-indented XML. If I call xw.WriteRaw() then that string is injected verbatim and does not follow my indentation I want.
...
string xml = ExternalMethod();
xw.WriteRaw(xml);
...
Essentially, I want a WriteRaw that will parse the XML string and go through all the WriteStartElement, etc. so that it gets reformatted per the XmlTextWriter's settings.
My preference is a way to do this with the setup I already have and to do this without having to reload the final XML just to reformat it. I'd also prefer not to parse the XML string with the likes of XmlReader and then mimic what it finds into my XmlWriter (very very manual process).
At the end of this I'd rather have a simple solution than one that follows my preferences. (Best solution, naturally, would be simple and follows my preferences.)
How about using a XmlReader to read the xml as xml nodes?
string xml = ExternalMethod();
XmlReader reader = XmlReader.Create(new StringReader(xml));
xw.WriteNode(reader, true);
You shouldn't use XmlTextWriter, as indicated in MSDN where it states:
In the .NET Framework version 2.0
release, the recommended practice is
to create XmlWriter instances using
the XmlWriter.Create method and the
XmlWriterSettings class. This allows
you to take full advantage of all the
new features introduced in this
release. For more information, see
Creating XML Writers.
Instead, you should use XmlWriter.Create to get your writer. You can then use the XmlWriterSettings class to specify things like indentation.
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = "\t";
Update
I think you can just use WriteNode. You take your xml string and load it into an XDocument or XmlReader and then use the node from that to write it into your XmlWriter.
This is the best I've got so far. A very manual process that only supports what is written. My string XML is nothing more than tags, attributes, and text data. If it supported namespaces, CDATA, etc. then this would have to grow accordingly.
Very manual, very messy and very likely prone to bugs but it does accomplish my preferences.
private static void PipeXMLIntoWriter(XmlWriter xw, string xml)
{
byte[] dat = new System.Text.UTF8Encoding().GetBytes(xml);
MemoryStream m = new MemoryStream();
m.Write(dat, 0, dat.Length);
m.Seek(0, SeekOrigin.Begin);
XmlReader r = XmlReader.Create(m);
while (r.Read())
{
switch (r.NodeType)
{
case XmlNodeType.Element:
xw.WriteStartElement(r.Name);
if (r.HasAttributes)
{
for (int i = 0; i < r.AttributeCount; i++)
{
r.MoveToAttribute(i);
xw.WriteAttributeString(r.Name, r.Value);
}
}
if (r.IsEmptyElement)
{
xw.WriteEndElement();
}
break;
case XmlNodeType.EndElement:
xw.WriteEndElement();
break;
case XmlNodeType.Text:
xw.WriteString(r.Value);
break;
default:
throw new Exception("Unrecognized node type: " + r.NodeType);
}
}
}
composing the answers above I have found this works:
private static string FormatXML(string unformattedXml) {
// first read the xml ignoring whitespace
XmlReaderSettings readeroptions= new XmlReaderSettings {IgnoreWhitespace = true};
XmlReader reader = XmlReader.Create(new StringReader(unformattedXml),readeroptions);
// then write it out with indentation
StringBuilder sb = new StringBuilder();
XmlWriterSettings xmlSettingsWithIndentation = new XmlWriterSettings { Indent = true};
using (XmlWriter writer = XmlWriter.Create(sb, xmlSettingsWithIndentation)) {
writer.WriteNode(reader, true);
}
return sb.ToString();
}
How about:
string xml = ExternalMethod();
var xd = XDocument.Parse(xml);
xd.WriteTo(xw);
I was looking for an answer to this issue but in VB.net.
Thanks to Colin Burnett, I solved it. I made two corrections: first, the XmlReader has to ignore white spaces (settings.IgnoreWhiteSpaces); second, the reader has to be back into the element after it reads attributes. Below you can see how the code looks like.
Also I tried the solution of GreyCloud, but in the generated XML there were some annoying empties attributes (xlmns).
Private Sub PipeXMLIntoWriter(xw As XmlWriter, xml As String)
Dim dat As Byte() = New System.Text.UTF8Encoding().GetBytes(xml)
Dim m As New MemoryStream()
m.Write(dat, 0, dat.Length)
m.Seek(0, SeekOrigin.Begin)
Dim settings As New XmlReaderSettings
settings.IgnoreWhitespace = True
settings.IgnoreComments = True
Dim r As XmlReader = XmlReader.Create(m, settings)
While r.Read()
Select Case r.NodeType
Case XmlNodeType.Element
xw.WriteStartElement(r.Name)
If r.HasAttributes Then
For i As Integer = 0 To r.AttributeCount - 1
r.MoveToAttribute(i)
xw.WriteAttributeString(r.Name, r.Value)
Next
r.MoveToElement()
End If
If r.IsEmptyElement Then
xw.WriteEndElement()
End If
Exit Select
Case XmlNodeType.EndElement
xw.WriteEndElement()
Exit Select
Case XmlNodeType.Text
xw.WriteString(r.Value)
Exit Select
Case Else
Throw New Exception("Unrecognized node type: " + r.NodeType)
End Select
End While
End Sub