How to serialize an c# object into xml without schema info? [duplicate] - c#

This question already has answers here:
How can I make the xmlserializer only serialize plain xml?
(4 answers)
Closed 8 years ago.
This is what I did:
A Serializable class:
[Serializable()]
public class Ticket
{
public string CitationNumber { get; set; }
public decimal Amount { get; set; }
}
Then serialize a model into xml:
var model = cart.Citations
.Select(c => new Ticket(c.Number, c.Amount)).ToList();
var serializer = new XmlSerializer(typeof (List<Ticket>));
var sw = new StringWriter();
serializer.Serialize(sw, model);
return sw.ToString();
The output sw.ToString() is like
<?xml version="1.0" encoding="utf-16"?>
<ArrayOfTicket xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Ticket>
<CitationNumber>00092844</CitationNumber>
<Amount>20</Amount>
</Ticket>
</ArrayOfTicket>
Is there a way to customize the Serialize() output to remove those schema info like: <?xml version="1.0" encoding="utf-16"?> and xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"?
And how can I change the root element ArrayOfTicket into something else?
Do I have control with those output?

You need a few xml tricks...
var serializer = new XmlSerializer(typeof(List<Ticket>));
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
var sw = new StringWriter();
var xmlWriter = XmlWriter.Create(sw, new XmlWriterSettings() { OmitXmlDeclaration = true });
serializer.Serialize(xmlWriter, model, ns);
string xml = sw.ToString();
Output:
<ArrayOfTicket>
<Ticket>
<CitationNumber>a</CitationNumber>
<Amount>1</Amount>
</Ticket>
<Ticket>
<CitationNumber>b</CitationNumber>
<Amount>2</Amount>
</Ticket>
</ArrayOfTicket>
PS: I added Indent = true to XmlWriterSettings to get the above output

Related

How to add to XmlDocument schema from XmlSchema object

I have problem with add schema to xml document. I added a schema to
the document and returning ActionResult I get an xml document without
a schema.
I defined the schema and added individual elements which I later added to the Xml document
How can I fix this problem?
[HttpGet("ConvertJsonToXML")]
[Produces("application/xml")]
public ActionResult ConvertJsonToXML(int? idProjectTlcStairsHistory)
{
//Find ID
var result = _project.FindProjectResult(idProjectTlcStairsHistory);
// Find name project
var nameProject = _project.ProjectName(idProjectTlcStairsHistory);
// Change format on improve format
var fileName = _project.ReplaceInvalidChars(nameProject);
JObject o = JObject.Parse(result);
XmlDocument doc = new XmlDocument();
string value = o.ToString();
doc = JsonConvert.DeserializeXmlNode(value, "StairsCalculationsData");
XmlSerializerNamespaces nameSpace = new XmlSerializerNamespaces();
nameSpace.Add("xsd", "http://www.w3.org/2001/XMLSchema");
//Schema
XmlSchema schema = new XmlSchema();
schema.ElementFormDefault = XmlSchemaForm.Qualified;
schema.AttributeFormDefault = XmlSchemaForm.Unqualified;
schema.Version = "1.0";
schema.Namespaces = nameSpace;
XmlSchemaSet schemaSet = new XmlSchemaSet();
schemaSet.Add(schema);
XmlSchemaElement element = new XmlSchemaElement();
element.Name = "SpiralStairs";
element.SchemaTypeName = new XmlQualifiedName("string",
"http://www.w3.org/2001/XMLSchema");
XmlAttribute attr = doc.CreateAttribute("myns:blah", "http://myns.com");
attr.Value = "my own attribute";
element.UnhandledAttributes = new XmlAttribute[] { attr };
schema.Items.Add(element);
doc.Schemas.Add(schema);
doc.Schemas.Add(schemaSet);
var file = XMLConvert.AddXmlDeclaration(doc);
doc.LoadXml(file);
doc.Save(#"C:\Projekty XML\" + fileName + ".xml");
return Ok(doc);
}
Result - the result he gets without a schematic
<?xml version="1.0" encoding="utf-8"?>
<StairsCalculationsData>
<centralPipeDiameter>150</centralPipeDiameter>
<leftTurn>false</leftTurn>
<rightTurn>true</rightTurn>
<stairsTurn>-1</stairsTurn>
<centralPipeHandrail>false</centralPipeHandrail>
<centralPipeHandrailRadius>120</centralPipeHandrailRadius>
<radius>1000</radius>
<walkingWidth>1185</walkingWidth>
<walkingLineRadius>1000</walkingLineRadius>
<secondWalkingLineRadius>0</secondWalkingLineRadius>
<isStandardRadius>true</isStandardRadius>
<isTlcStandard>true</isTlcStandard>
<maxStepHeight>240</maxStepHeight>
<selectedRadius>1300</selectedRadius>
<selectedStep />
<levels>
<levelNumber>0</levelNumber>
<landing>
<initialDirection>4</initialDirection>
<landingShape>0</landingShape>
<startEdgeHeight>100</startEdgeHeight>
<endEdgeHeight>100</endEdgeHeight>
<startLandingAngle>90</startLandingAngle>
<endLandingAngle>0</endLandingAngle>
<isLandingAngleProperly>true</isLandingAngleProperly>
<landingWidth>1570.7963267948965</landingWidth>
<landingAngle>90</landingAngle>
</landing>
<isLastLevel>false</isLastLevel>
<angleNextLevel>20</angleNextLevel>
<startFlightAngleFromNextLevel>0</startFlightAngleFromNextLevel>
<levelMessages />
<isStepWidthProperly>true</isStepWidthProperly>
<stepDeepInWalkingLine>347.3</stepDeepInWalkingLine>
<heightLevel>2750</heightLevel>
<isStepHeightProperly>false</isStepHeightProperly>
<stepHeight>114.58333333333333</stepHeight>
<rotationRange>1.2777777777777777</rotationRange>
<startFlightAngle>190</startFlightAngle>
<flightRotationRangeAngle>460</flightRotationRangeAngle>
<stepAngle>20</stepAngle>
<isStepsAmountProperly>true</isStepsAmountProperly>
<stepsAmount>24</stepsAmount>
<stepsPerTurn>18</stepsPerTurn>
<isAngleDiffProperly>true</isAngleDiffProperly>
<angleDiff>0</angleDiff>
<isConvinienceProperly>false</isConvinienceProperly>
<convinience>576.47</convinience>
<isFreeSpaceByHeliceProperly>false</isFreeSpaceByHeliceProperly>
<endFreeSpaceByHelice>1440.2</endFreeSpaceByHelice>
<isFreeSpaceProperly>false</isFreeSpaceProperly>
<endFreeSpace>1504.2</endFreeSpace>
<isFlightFreeSpaceProperly>false</isFlightFreeSpaceProperly>
<flightFreeSpace>1847.9</flightFreeSpace>
<isFreeSpaceAboveLandingsProperly>true</isFreeSpaceAboveLandingsProperly>
<freeSpaceAboveLandings>2800</freeSpaceAboveLandings>
</levels>
</StairsCalculationsData>
How add to xml information from schema?
Example:
<xsd:schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" attributeFormDefault="unqualified" elementFormDefault="qualified" version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element myns:blah="my own attribute" name="SpiralStairs" type="xsd:string" xmlns:myns="http://myns.com" />
</xsd:schema>

Remove the root when serializing/deserializing XML

I'm using the XmlReader and XmlWriter classes along with the XmlSerializer class to serialize and deserialize some XML models. Sadly, the format of the XML is out of my hands, and one of the files expects an invalid format, something like this:
<?xml version="1.0"?>
<some_element>...</some_element>
<some_element>...</some_element>
<some_element>...</some_element>
Basically, it doesn't have a singleton root node. Can I make the serializer somehow read and reproduce such a format?
Note: I'd like to stick to the standard interface (IXmlSerializable), so I don't have to differentiate between this and other models.
Edit:
I've tried to implement IXmlSerializable explicitly for the type:
public class TheInvalidModel : IXmlSerializable
{
[XmlElement("some_element")]
public List<SomeElement> Elements { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
// TODO
}
public void WriteXml(XmlWriter writer)
{
var ser = new XmlSerializer(typeof(SomeElement));
foreach (var e in Elements)
{
ser .Serialize(writer, e);
}
}
}
Sadly, this automatically writes out a root element.
Edit 2:
With this sample:
var model = new TheInvalidModel
{
Elements = new List<SomeElement>
{
new SomeElement { },
new SomeElement { },
new SomeElement { },
}
};
var serializer = new XmlSerializer(typeof(TheInvalidModel));
var tw = new StringWriter();
serializer.Serialize(tw, model);
Console.WriteLine(tw.ToString());
I get the following output:
<?xml version="1.0" encoding="utf-16"?>
<TheInvalidModel>
<SomeElement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />
<SomeElement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />
<SomeElement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />
</TheInvalidModel>
But what I'd need instead is:
<?xml version="1.0" encoding="utf-16"?>
<SomeElement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />
<SomeElement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />
<SomeElement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />
You could write non-conformant xml code with a more manual approach;
https://learn.microsoft.com/en-us/dotnet/api/system.xml.xmlwritersettings.conformancelevel?view=netcore-3.1
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
settings.ConformanceLevel = ConformanceLevel.Fragment;
settings.CloseOutput = false;
// Create the XmlWriter object and write some content.
MemoryStream strm = new MemoryStream();
XmlWriter writer = XmlWriter.Create(strm, settings);
writer.WriteElementString("orderID", "1-456-ab");
writer.WriteElementString("orderID", "2-36-00a");
writer.Flush();
writer.Close();
// Do additional processing on the stream.
With this you could loop your SomeElements list and output the xml.
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string INPUT_FILENAME = #"c:\temp\test.xml";
const string OUTPUT_FILENAME = #"c:\temp\test1.xml";
static void Main(string[] args)
{
StringBuilder builder = new StringBuilder(File.ReadAllText(INPUT_FILENAME));
StringWriter tw = new StringWriter(builder);
//fill string writer with existing code
//I just used input file for testing
XElement model = XElement.Parse(tw.ToString());
string ident = "<?xml version=\"1.0\" encoding=\"utf-16\"?>";
StreamWriter writer = new StreamWriter(OUTPUT_FILENAME);
writer.WriteLine(ident);
foreach(XElement someElement in model.Descendants("SomeElement"))
{
writer.WriteLine(someElement);
}
writer.Flush();
writer.Close();
}
}
}

Serialize object into XML including "xsi:schemaLocation" and order of attributes

I have this class
public class EnvioDTE
{
[XmlAttribute]
public string version { get; set; }
public EnvioDTE()
{
this.version = "1.0";
}
}
I am serializing it to XML with the following code:
EnvioDTE envioDTE = new EnvioDTE();
string xml = "";
var serializer = new XmlSerializer(typeof(EnvioDTE));
var settings = new XmlWriterSettings
{
Indent = true,
NewLineChars = "\n",
OmitXmlDeclaration = false,
Encoding = Encoding.GetEncoding("ISO-8859-1")
};
using (var stream = new MemoryStream())
{
using (var xmlWriter = XmlWriter.Create(stream, settings))
{
serializer.Serialize(xmlWriter, this);
xml = Encoding.GetEncoding("ISO-8859-1").GetString(stream.ToArray());
}
}
Console.WriteLine(xml);
Which is giving me the following XML:
<?xml version="1.0" encoding="iso-8859-1"?>
<EnvioDTE version="1.0">
</EnvioDTE>
What do I need to add to my code so that I get the following attributes?
<?xml version="1.0" encoding="iso-8859-1"?>
<EnvioDTE xmlns="http://www.sii.cl/SiiDte" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sii.cl/SiiDte EnvioDTE_v10.xsd" version="1.0">
</EnvioDTE>
The order of the attributes is important for me.
I tried by making two changes:
Change #1
[XmlRoot(Namespace = "http://www.sii.cl/SiiDte")] // *** NEW
public class EnvioDTE
{
[XmlAttribute("schemaLocation", Namespace = "http://www.w3.org/2001/XMLSchema-instance")] // *** NEW
public string schemaLocation { get; set; } // *** NEW
[XmlAttribute]
public string version { get; set; }
public EnvioDTE()
{
this.version = "1.0";
}
}
Change #2
EnvioDTE envioDTE = new EnvioDTE();
string xml = "";
var namespaces = new XmlSerializerNamespaces(); // *** NEW
namespaces.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance"); // *** NEW
var serializer = new XmlSerializer(typeof(EnvioDTE));
var settings = new XmlWriterSettings
{
Indent = true,
NewLineChars = "\n",
OmitXmlDeclaration = false,
Encoding = Encoding.GetEncoding("ISO-8859-1")
};
using (var stream = new MemoryStream())
{
using (var xmlWriter = XmlWriter.Create(stream, settings))
{
serializer.Serialize(xmlWriter, this, namespaces); // *** NEW
xml = Encoding.GetEncoding("ISO-8859-1").GetString(stream.ToArray());
}
}
Console.WriteLine(xml);
With those changes I'm getting this:
<?xml version="1.0" encoding="iso-8859-1"?>
<EnvioDTE xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sii.cl/SiiDte EnvioDTE_v10.xsd" version="1.0" xmlns="http://www.sii.cl/SiiDte">
</EnvioDTE>
And that is not the order of attributes I want...
So you are just trying to read out the XML? I would do this:
XmlReader reader = XmlReader.Create(path, settings);
StringBuilder sb = new StringBuilder();
if (reader != null)
{
while (reader.Read())
{
sb.AppendLine(reader.ReadOuterXml());
}
doc = new XmlDocument();
doc.LoadXml(Convert.ToString(sb));
XmlNodeList xmlNodeList;
xmlNodeList = doc.GetElementsByTagName("Whatever your tag name");
for (i = 0; i < xmlNodeList.Count; i++)
{
if (xmlNodeList[i].InnerXml.Length > 0)
{
foo = xmlNodeList[i].InnerXml;
}
}
}
Okay, you are just trying to output? Then do this. I know it's a bit of a hack and there is probably a million ways to do it:
string myXMLstring = "<?xml version=\"1.0\" encoding="iso-8859-1\"?>" +
<EnvioDTE xmlns=\"http://www.sii.cl/SiiDte\"" +
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +
"xsi:schemaLocation=\"http://www.sii.cl/SiiDte EnvioDTE_v10.xsd\"" +
"version=\"1.0\">" +
"</EnvioDTE>";
I've escaped the the quotes and built it up as a string. You can even add \r\n anytime you know you need a new line. I hope that helps. Happy coding!

C# append object to xml file using serialization

I am trying append a serialized object to an existing xml file beneath the root element, which I thought would be simple but is proving to be a little challenging.
The problem is in the AddShortcut method but I added some more code for completeness.
I believe what I need to do is:
load the file into an XmlDocument.
navigate to the node I want to append beneath (here the node name is Shortcuts).
create some type of writer and then serialize the object.
save the XmlDocument.
The trouble is in steps 2 and 3. I have tried different variations but I think using XPathNavigator somehow to find the "root" node to append under is a step in the right direction.
I have also looked at almost every question on Stack Overflow on the subject.
Any suggestions welcome. Here is my code
class XmlEngine
{
public string FullPath { get; set; } // the full path to the xmlDocument
private readonly XmlDocument xDoc;
public XmlEngine(string fullPath, string startElement, string[] rElements)
{
FullPath = fullPath;
xDoc = new XmlDocument();
CreateXmlFile(FullPath, startElement, rElements);
}
public void CreateXmlFile(string path, string startElement, string[] rElements)
{
try
{
if (!File.Exists(path))
{
// create a txt writer
XmlTextWriter wtr = new XmlTextWriter(path, System.Text.Encoding.UTF8);
// make sure the file is well formatted
wtr.Formatting = Formatting.Indented;
wtr.WriteProcessingInstruction("xml", "version='1.0' encoding='UTF-8'");
wtr.WriteStartElement(startElement);
wtr.Close();
// write the top level root elements
writeRootElements(path, rElements);
}
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
Console.WriteLine("Could not create file: " + path);
}
}
public void AddShortcut(Shortcut s)
{
xDoc.Load(FullPath);
rootNode = xDoc.AppendChild(xDoc.CreateElement("Shortcuts"));
var serializer = new XmlSerializer(s.GetType());
using (var writer = new StreamWriter(FullPath, true))
{
XmlWriterSettings ws = new XmlWriterSettings();
ws.OmitXmlDeclaration = true;
serializer.Serialize(writer, s);
}
xDoc.Save(FullPath);
}
}
This code sample worked for me:
xml:
<?xml version="1.0" encoding="UTF-8"?>
<Launchpad>
<Shortcuts>
<Shortcut Id="1">
<Type>Folder</Type>
<FullPath>C:\SomePath</FullPath>
<Name>SomeFolderName</Name>
</Shortcut>
</Shortcuts>
</Launchpad>
Method:
public void AddShortcut(Shortcut s)
{
xDoc.Load(FullPath);
var rootNode = xDoc.GetElementsByTagName("Shortcuts")[0];
var nav = rootNode.CreateNavigator();
var emptyNamepsaces = new XmlSerializerNamespaces(new[] {
XmlQualifiedName.Empty
});
using (var writer = nav.AppendChild())
{
var serializer = new XmlSerializer(s.GetType());
writer.WriteWhitespace("");
serializer.Serialize(writer, s, emptyNamepsaces);
writer.Close();
}
xDoc.Save(FullPath);
}
load the file into an XmlDocument.
navigate to the node I want to append beneath (here the node name is Shortcuts).
create some type of writer and then serialize the object.
save the XmlDocument
So:
public void AddShortcut(Shortcut s)
{
// 1. load existing xml
xDoc.Load(FullPath);
// 2. create an XML node from object
XmlElement node = SerializeToXmlElement(s);
// 3. append that node to Shortcuts node under XML root
var shortcutsNode = xDoc.CreateElement("Shortcuts")
shortcutsNode.AppendChild(node);
xDoc.DocumentElement.AppendChild(shortcutsNode);
// 4. save changes
xDoc.Save(FullPath);
}
public static XmlElement SerializeToXmlElement(object o)
{
XmlDocument doc = new XmlDocument();
using(XmlWriter writer = doc.CreateNavigator().AppendChild())
{
new XmlSerializer(o.GetType()).Serialize(writer, o);
}
return doc.DocumentElement;
}
This post

How To get xml node from object of type T?

I am trying to convert the object of type T into xml node because I want to display the xml node in a wpf control. Below is the linqpad snippet, I am working with:
[Serializable]
public class test {
public int int1 { get ; set ;}
public int int2 { get ; set ;}
public string str1 { get ; set ;}
}
void Main()
{
test t1 = new test () ;
t1.int1 = 12 ;
t1.int2 = 23 ;
t1.str1 = "hello" ;
System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(t1.GetType());
StringWriter sww = new StringWriter();
XmlWriter writer = XmlWriter.Create(sww);
x.Serialize(writer, t1);
var xml = sww.XmlSerializeToXElement ();
xml.Dump () ;
}
I am not getting intended result and instead, I am getting this:
<StringWriter xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<NewLine>
</NewLine>
</StringWriter>
If you are trying to get an XElement, the xml.Root is what you want:
System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(t1.GetType());
StringWriter sww = new StringWriter();
XmlWriter writer = XmlWriter.Create(sww);
x.Serialize(writer, t1);
var xml = XDocument.Parse(sww.ToString());
Console.WriteLine(xml.Root);
Output:
<test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<int1>12</int1>
<int2>23</int2>
<str1>hello</str1>
</test>

Categories