Add new XElements with new line in XDocument with PreserveWhitespace LoadOptions - c#

I'm trying to edit XML file saving its format:
<root>
<files>
<file>a</file>
<file>b</file>
<file>c</file>
<file>d</file>
</files>
</root>
So i load xml document using XDocument xDoc = XDocument.Load(path, LoadOptions.PreserveWhitespace);
But when i'm trying to add new elements xDoc.Root.Element("files").Add(new XElement("test","test"));
xDoc.Root.Element("files").Add(new XElement("test2","test2"));
it adds in the same line, so output is like:
<root>
<files>
<file>a</file>
<file>b</file>
<file>c</file>
<file>d</file>
<test>test</test><test2>test2</test2></files>
</root>
So how can i add new elements each on new line saving initial formatting? I tried to use XmlWriter with Setting.Indent = true to save XDocument, but as i see, elements are added to the same line, when i use xDoc.Root.Element().Add()
Update: full part of program loading, modifying and saving document
using System;
using System.Xml;
using System.Xml.Linq;
using System.Text;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
string path = #".\doc.xml";
XDocument xDoc = XDocument.Load(path, LoadOptions.PreserveWhitespace);
//when i debug i see in "watch" that after these commands new elements are already added in same line
xDoc.Descendants("files").First().Add(new XElement("test", "test"));
xDoc.Descendants("files").First().Add(new XElement("test2", "test2"));
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.UTF8;
settings.Indent = true;
settings.IndentChars = "\t";
using (XmlWriter writer = XmlTextWriter.Create(path, settings))
{
xDoc.Save(writer);
//Here i also tried save without writer - xDoc.Save(path)
}
}
}
}

The problem appears to be caused by your use of LoadOptions.PreserveWhitespace. This seems to trump XmlWriterSettings.Indent - you've basically said, "I care about this whitespace"... "Oh, now I don't."
If you remove that option, just using:
XDocument xDoc = XDocument.Load(path);
... then it indents appropriately. If you want to preserve all the original whitespace but then indent just the new elements, I think you'll need to add that indentation yourself.

I had a similar problem and I could solve with the code below:
var newPolygon = new XElement(doc.Root.GetDefaultNamespace() + "polygon");
groupElement.Add(newPolygon);
groupElement.Add(Environment.NewLine);
I hope this code can help some people...

Related

Indenting Xml file edited with XDocument in C#

I have some code that edits and Xml file.
When I save the file the new elements are not properly indented while existing elements are, e.g.:
Before:
<MyGroup>
<ExistingElement1>a value</ExistingElement1>
<ExistingElement2>something else</ExistingElement2>
</MyGroup>
After:
<MyGroup>
<ExistingElement1>a value</ExistingElement1>
<ExistingElement2>something else</ExistingElement2>
<NewElement>Inserted by code</NewElement></MyGroup>
New elements are added with XElement, like:
myGroup.Add(new XElement(ns + "NewElement", "Inserted by code"));
when saving the file I use XmlWriterSettings as I want to avoid saving the XmlDeclaration:
var settings = new XmlWriterSettings
{
OmitXmlDeclaration = true,
Encoding = Encoding.UTF8,
Indent = true
};
using (var writer = XmlWriter.Create(filePath, settings))
{
xmlDoc.Save(writer);
}
So it looks like that the Indent = true option is not working for the newly added elements, does anyone know why?
BTW, when I open the file I use LoadOptions.PreserveWhitespace
XDocument xmlDoc = XDocument.Load(filePath, LoadOptions.PreserveWhitespace);

XML Parsing Error: no element found message and empty document creation

I'm trying to create an xml file. I already set the document and have a result with Xmlwriter when printing to console but when it comes to having an actual .xml file on my desktop I always end up with empty files. Clearly I'm missing something or forgetting something but can't tell on my own.
Below is the piece of my code where it all happens (not).
public void button1_Click(object sender, EventArgs e)
{
XmlDocument dddxml = new XmlDocument();
//XmlDeclaration xmldecl;
//xmldecl = dddxml.CreateXmlDeclaration("1.0", null, null);
//xmldecl.Encoding = "UTF-8";
//xmldecl.Standalone = "yes";
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.UTF8;
settings.Indent = true;
StringBuilder builder = new StringBuilder();
writer = XmlWriter.Create(builder, settings);
writer.WriteStartDocument();
writer.WriteStartElement("root");
BlockSelect(0);
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Close();
Console.WriteLine(builder.ToString());
writer = XmlWriter.Create("DddXml.Xml", settings);
dddxml.Save(writer);
File.Create(path);//declared elsewhere, valid file location string
}
You have created new XmlDocument here:
XmlDocument dddxml = new XmlDocument();
But you haven't populated it in the rest of the code and in fact you're not using it and writing xml to string builder using WriteStartDocument and WriteEndElement methods of XmlWriter.
Thus your dddxml remains empty, so when you're trying to save it like this:
dddxml.Save(writer);
, there is nothing to save and you're getting empty file.
So you have to choose - will you use XmlDocument or XmlWriter to create and save your xml.
As commented by #Charles Mager, File.Create() just makes an empty file.
You can try to write directly to the file instead of using StringBuilder. Here's a sample to directly write to the file using the XmlWriter:
XmlWriter writer = XmlWriter.Create("C:\\ddxml.xml", settings);
writer.WriteStartDocument();
writer.WriteStartElement("root");
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Close();
See that the file is written on C:\ddxml.xml.
If you want you can also use LINQ, it's easier :
XDocument doc = new XDocument();
XNamespace ns = "";
doc.Add(new XElement(ns + "root"));
doc.Save(#"C:\DddXml.Xml");

XML Extra free space

Good day, in general is a problem, I work with XML through C# XMLdocument, after saving that "document", there is such a thing: 
<Name></Name>
After saving:
<Name>
</Name>
How to remove extra spaces?  I've tried: doc.PreserveWhitespace=true;  before saving and before loading. The result is not one that removes all spaces. XML document (large volume) become visually unreadable.
I have already tried, same result. And need Encoding windows-1251 Why XmlDocument do this bad thing? That free or whitespace important for me and my "program".
the problem is solved. thank you all
It can be done. You've got to help control the formatting options when you save the document:
XmlDocument doc = new XmlDocument();
using (var wr = new XmlTextWriter(fileName))
{
wr.Formatting = Formatting.None;
doc.Save(wr);
}
Or you can fine-tune it further with XmlWriterSettings:
var settings = new XmlWriterSettings
{
Indent = false,
NewLineChars = String.Empty
};
using (var wr = XmlWriter.Create(fileName, settings))
{
wr.Formatting = Formatting.None;
doc.Save(wr);
}

Root Element Missing - Creating Xmldocument using XmlTextWriter

I'm having the following code which is spitting 'Root Element Missing' during doc.Load().
MemoryStream stream = new MemoryStream();
XmlTextWriter xmlWriter = new XmlTextWriter(stream, Encoding.UTF8);
xmlWriter.Formatting = System.Xml.Formatting.Indented;
xmlWriter.WriteStartDocument();
xmlWriter.WriteStartElement("Root");
XmlDocument doc = new XmlDocument();
stream.Position = 0;
doc.Load(stream);
xmlWriter.Close();
I'm not able to figure out the issue. Any insights?
You haven't flushed the xmlWriter, so it may well not have written anything out yet. Also, you're never completing the root element, so even if it has written out
<Root>
it won't have written the closing tag. You're trying to load it as a complete document.
I'm not sure at what point an XmlWriter actually writes out the starting part of an element anyway - don't forget it may have attributes to write too. The most it could write out with the code you've got is <Root.
Here's a complete program which works:
using System;
using System.IO;
using System.Text;
using System.Xml;
class Test
{
static void Main(string[] args)
{
using (MemoryStream stream = new MemoryStream())
{
XmlTextWriter xmlWriter = new XmlTextWriter(stream, Encoding.UTF8);
xmlWriter.Formatting = System.Xml.Formatting.Indented;
xmlWriter.WriteStartDocument();
xmlWriter.WriteStartElement("Root");
xmlWriter.WriteEndElement();
xmlWriter.Flush();
XmlDocument doc = new XmlDocument();
stream.Position = 0;
doc.Load(stream);
doc.Save(Console.Out);
}
}
}
(Note that I'm not calling WriteEndDocument - that only seems to be necessary if you still have open elements or attributes.)
What #Skeet said, plus, you don't seem to close your element:
xmlWriter.WriteEndElement();
Well I see you starting the document, but I don't see you ending it or closing it... (at least not before you use it)

C#: A simple way to bring One-line-XML-files to human readable multi line

I'm looking for a simply way to bring a xml-File with one line without line feeds to a good structured human readable version in C#. Is there any Implementation already in System.XML or a tiny open source framework or a best practice for implementing it?
ex. transform this XML-String:
<Root><Node id="1"><Childnode>Text</Childnode></Node><Node id="2">Text<Kid name="jack" /></Node></Root>
to
<Root>
<Node id="1">
<Childnode>
Text
</Childnode>
</Node>
<Node id="2">
Text
<Kid name="jack" />
</Node>
</Root>
If you have .NET 3.5:
XDocument document = XDocument.Load(filename);
document.Save(filename);
This will indent automatically. Note that it won't do quite as your question asked, because you're only indenting some of the nodes. That's going to be trickier.
If you're stuck with .NET 2.0, here's Craig's method rejigged and changed to use files instead of strings:
public static void FormatXmlString(string inputFile, string outputFile)
{
XmlDocument document = new XmlDocument();
document.Load(inputFile);
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
using (XmlWriter writer = XmlWriter.Create(outputFile, settings))
{
document.WriteTo(writer);
}
}
With C# 3 the XmlWriterSettings but could just be:
new XmlWriterSettings { Indent = true }
which could be embedded in the call to XmlWriter.Create, but if you're using .NET 2.0 you probably can't use C# 3.
EDIT: If the input filename part causes a problem, you can use:
XmlDocument document = new XmlDocument();
using (Stream stream = File.OpenRead(inputFile))
{
document.Load(stream);
}
Here's a handy "FormatXML" class that I wrote for just this purpose:
using System;
using System.Text;
using System.Xml;
using System.IO;
public static class FormatXML
{
public static string FormatXMLString(string sUnformattedXML)
{
XmlDocument xd = new XmlDocument();
xd.LoadXml(sUnformattedXML);
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
XmlTextWriter xtw = null;
try
{
xtw = new XmlTextWriter(sw);
xtw.Formatting = Formatting.Indented;
xd.WriteTo(xtw);
}
finally
{
if(xtw!=null)
xtw.Close();
}
return sb.ToString();
}
}
If you have got Visual Studio:
Create a new XML file and just paste your code. It will re-format it automatically.

Categories