Not Writing data to xml file as expected - c#

there are some records in the recordlist but when I am calling the following method, it is not writing the data to xml. it is just writing .
I am absolutely new to XML. Please help me.
public void SaveRentalRecords()
{
// create the XmlWriterSettings object
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = (" ");
// create the XmlWriter object
XmlWriter xmlOut = XmlWriter.Create(path, settings);
// write the start of the document
xmlOut.WriteStartDocument();
xmlOut.WriteStartElement("RentalRecords");
// write each Product object to the xml file
foreach (RecordList record in Records)
{
xmlOut.WriteStartElement("RentalRecord");
xmlOut.WriteElementString("TenantID", record.TenantID);
xmlOut.WriteElementString("TenantName", record.TenantName);
xmlOut.WriteElementString("PropertyID", record.PropertyID);
xmlOut.WriteElementString("PropertyAddress", record.PropertyAddress);
xmlOut.WriteEndElement();
MessageBox.Show(record.TenantID+record.TenantName+record.PropertyID+record.PropertyAddress);
}
// write the end tag for the root element
xmlOut.WriteEndElement();
// close the XmlWriter object
xmlOut.Close();
}

You can try the below approach :
var result = new XElement("RentalRecords", new XElement("RentalRecord", recs.Select(x => new XElement(x.tenantId.ToString(CultureInfo.InvariantCulture), x.tenantName, x.PropertyId.ToString(CultureInfo.InvariantCulture), x.PropertyName))));
result.Save("RentalRecords.xml");

Related

How to write C# DataSet object to XML with customized nodes structure?

I have a similar case - I receive a DataSet object with data tables willed with data (e. g. customers table ...) from an external module (done by other programmer).
I then save the data set object to an xml using the writeXml method - here is my code
public void Save(string myXmlFilePath)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = System.Text.Encoding.UTF8;
settings.Indent = true;
settings.NewLineHandling = NewLineHandling.None;
using (XmlWriter writer = XmlWriter.Create(myXmlFilePath, settings))
{
ExportObject.WriteXml(writer);
writer.Close();
}
}
I get the standard xml file output structure like this:
<NewDataSet>
<Customers>...</Customers>
<Customers>...</Customers>
<NewDataSet>`
However I want the structure like this
<Customers>
<Customer>...</Customer>
<Customer>...</Customer>
</Customers>`
How can I achieve this?
Specify the desired names to the dataset and the tables within it.
ExportObject.DataSetName = "Customers";
ExportObject.Tables[0].TableName = "Customer";
A work around is to let WriteXml write however it likes and then do an XSD transform to the format you prefer.

Inserting new data into xml from datatable

I have an xml file about 900MB and i want to insert data from datatable to that existing xml.
There is a way to do this by using load and save like below;
XDocument xdoc = XDocument.Load(FilePath);
var root = xdoc.Descendants("DocumentElement").FirstOrDefault()
if (root != null){
root.Add(new XElement("tag", "value"));
xdoc.Save(FilePath);
}
However, its cost too much. Loading 900MB xml into datatable can cause memory exceptions and poor performance for couple of new rows.
How can i add new rows to big existing xml from datatable?
XDocument (and XmlDocument as well) loads whole file into memory. You should use XmlWriter with combination of XNode.WriteTo method
Example from XNode.WriteTo documentation:
StringBuilder sb = new StringBuilder();
XmlWriterSettings xws = new XmlWriterSettings();
xws.OmitXmlDeclaration = true;
xws.Indent = true;
using (XmlWriter xw = XmlWriter.Create(sb, xws))
{
XElement child2 = new XElement("AnotherChild",
new XElement("GrandChild", "different content"));
child2.WriteTo(xw);
xw.WriteEndElement();
}
Console.WriteLine(sb.ToString());
You can read big xml documents in the same way, check example in XNode.ReadFrom documentation

XmlTextWriter serialize Object to XML element

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.

How do I make XmlSerialiser not start with <?xml ?>?

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();
}
}

XML indenting when injecting an XML string into an XmlWriter

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

Categories

Resources