The file format I'm working with (OFX) is XML-like and contains a bunch of plain-text stuff before the XML-like bit begins. It doesn't like having between the plain-text and XML parts though, so I'm wondering if there's a way to get XmlSerialiser to ignore that. I know I could go through the file and wipe out that line but it would be simpler and cleaner to not write it in the first place! Any ideas?
You'll have to manipulate the XML writer object you use when calling the Serialize method. Its Settings property has a OmitXmlDeclaration property, which you'll want to set to true. You'll also need to set the ConformanceLevel property, otherwise the XmlWriter will ignore the OmitXmlDeclaration property.
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
settings.ConformanceLevel = ConformanceLevel.Fragment;
XmlWriter writer = XmlWriter.Create(/*whatever stream you need*/,settings);
serializer.Serialize(writer,objectToSerialize);
writer.close();
Not too tough, you just have to serialize to an explicitly declared XmlWriter and set the options on that writer before you serialize.
public static string SerializeExplicit(SomeObject obj)
{
XmlWriterSettings settings;
settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
XmlSerializerNamespaces ns;
ns = new XmlSerializerNamespaces();
ns.Add("", "");
XmlSerializer serializer;
serializer = new XmlSerializer(typeof(SomeObject));
//Or, you can pass a stream in to this function and serialize to it.
// or a file, or whatever - this just returns the string for demo purposes.
StringBuilder sb = new StringBuilder();
using(var xwriter = XmlWriter.Create(sb, settings))
{
serializer.Serialize(xwriter, obj, ns);
return sb.ToString();
}
}
Related
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.
When using the default settings with the XmlSerializer it will output the XML as a formated value.
IE: something along these lines.
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfStock xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Stock>
<ProductCode>12345</ProductCode>
<ProductPrice>10.32</ProductPrice>
</Stock>
<Stock>
<ProductCode>45632</ProductCode>
<ProductPrice>5.43</ProductPrice>
</Stock>
</ArrayOfStock>
How does one prevent any type of formatting on the output? So what I am looking to achieve is this.
<?xml version="1.0" encoding="utf-8"?><ArrayOfStock xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><Stock><ProductCode>123456</ProductCode><ProductPrice>10.57</ProductPrice></Stock><Stock><ProductCode>789123</ProductCode><ProductPrice>133.22</ProductPrice></Stock></ArrayOfStock>
EDIT: The full code of my method is
public static String Serialize(Stock stock)
{
XmlSerializer serializer = new XmlSerializer(typeof(Stock));
using (StringWriter stringWriter = new StringWriter())
{
serializer.Serialize(stringWriter, stock);
return stringWriter.ToString();
}
}
Not very intuitive, but the Indent property on the XmlWriterSettings controls the whole formatting:
var serializer = new XmlSerializer(typeof(MyClass));
using (var writer = new StreamWriter("file.path"))
using (var xmlWriter = XmlWriter.Create(writer, new XmlWriterSettings { Indent = false }))
{
serializer.Serialize(xmlWriter, myObject);
}
There are a few more options on XmlWriterSettings that you might want to explore.
It is simple to parse the resulting XML and remove and newlines and tabs...
using 'Indent = false', will still put elements on newlines no?
..
XmlSerializer xmlser = new XmlSerializer(...);
XmlWriterSettings settings = new XmlWriterSettings {Indent = false};
using (XmlWriter xw = XmlWriter.Create(stream, settings))
{
...
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);
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
I am editing csproj files with Linq-to-XML and need to save the XML without the <?XML?> header.
As XDocument.Save() is missing the necessary option, what's the best way to do this?
You can do this with XmlWriterSettings, and saving the document to an XmlWriter:
XDocument doc = new XDocument(new XElement("foo",
new XAttribute("hello","world")));
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
StringWriter sw = new StringWriter();
using (XmlWriter xw = XmlWriter.Create(sw, settings))
// or to write to a file...
//using (XmlWriter xw = XmlWriter.Create(filePath, settings))
{
doc.Save(xw);
}
string s = sw.ToString();
A simpler solution than the accepted answer is to use XDocument.ToString() to get the XML text without the header.
Example:
// Load the file
XDocument xDocument = XDocument.Load(fileName);
// Edit the XML...
// Save the edited XML text to file
File.WriteAllText(fileName, xDocument.ToString());