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!
Related
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();
}
}
}
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
this is my cod i want with this get all file in directory and end write all in xml file
private void button3_Click(object sender, EventArgs e)
{
XmlDocument doc = new XmlDocument();
string appPath = Path.GetDirectoryName(Application.ExecutablePath);
string folder = appPath;//Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + #"\Archive\";
string filter = "*.*";
string[] files = Directory.GetFiles(folder, filter);
foreach (string item in files)
{
string string1 = item;
string string2 = appPath;
string result = string1.Replace(string2, "");
MessageBox.Show(result);
doc.LoadXml("<item><name>#" + result + " </name></item>");
// Save the document to a file and auto-indent the output.
using (XmlTextWriter writer = new XmlTextWriter("data.xml", null))
{
writer.Formatting = Formatting.Indented;
doc.Save(writer);
writer.Close();
}
}
}
with this code i get my file in directory and remove path
for example C://folder1/folder2/bin/app.exe
to app.exe
its okay but in the end in xml just write one file
XML Result
<?xml version="1.0"?>
<item>
<name>#\WindowsFormsApplication8.vshost.exe.manifest </name>
</item>
Here:
doc.LoadXml("<item><name>#" + result + " </name></item>");
Every time your loop repeats, you're overwriting all of the XML in your XmlDocument.
If you want to use XmlDocument, try this instead, although there are other (Cleaner) ways to output XML.
var doc = new XmlDocument();
var root = doc.AppendChild(doc.CreateElement("Item"));
foreach (var item in files)
{
var name = root.AppendChild(doc.CreateElement("Name"));
name.InnerText = item;
}
var xmlWriterSettings = new XmlWriterSettings { Indent = true };
using (var writer = XmlWriter.Create("data.xml", xmlWriterSettings))
{
doc.Save(writer);
}
Using XmlSerialiser (cleaner C# code than XDocument):
public class Program
{
[XmlType("Item")]
public class Item
{
[XmlElement("Name")]
public string[] Files { get; set; }
}
static string SerialiseToXml<T>(T obj, bool isFormatted = false)
{
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
var stringBuilder = new StringBuilder();
var xmlWriterSettings = new XmlWriterSettings { OmitXmlDeclaration = true, Indent = isFormatted };
using (var xmlWriter = XmlWriter.Create(stringBuilder, xmlWriterSettings))
{
var serializer = new XmlSerializer(obj.GetType());
serializer.Serialize(xmlWriter, obj, ns);
return stringBuilder.ToString();
}
}
static void Main(string[] args)
{
string[] files = {"Apple.txt", "Orange.exe", "Pear.docx", "Banana.xml", "Papaya.xls", "Passionfruit.cs"};
var item = new Item {Files = files};
var xml = SerialiseToXml(item, true);
Console.WriteLine(xml);
}
}
You are overwriting your items.
Here's the code that will write a proper xml:
XmlDocument doc = new XmlDocument();
string appPath = Directory.GetCurrentDirectory();
string folder = appPath;
string filter = "*.*";
string[] files = Directory.GetFiles(folder, filter);
using (XmlTextWriter writer = new XmlTextWriter("data.xml", null))
{
writer.WriteStartDocument();
writer.WriteStartElement("Items");
foreach (string item in files)
{
string string1 = item;
string string2 = appPath;
string result = string1.Replace(string2, "");
writer.WriteElementString("Item","", result);
Console.WriteLine(result);
writer.Formatting = Formatting.Indented;
}
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Close();
doc.Save(writer);
}
And here's the sample xml,
<?xml version="1.0"?>
<Items>
<Item>\ConsoleApplication1.exe</Item>
<Item>\ConsoleApplication1.exe.config</Item>
<Item>\ConsoleApplication1.pdb</Item>
<Item>\ConsoleApplication1.vshost.exe</Item>
<Item>\ConsoleApplication1.vshost.exe.config</Item>
<Item>\ConsoleApplication1.vshost.exe.manifest</Item>
<Item>\data.xml</Item>
</Items>
thanks for best answers.
in my directory too i have 3 folder and There are more files in any folder ,i want any files in folders write in my xml
For Example
<Items>
<Item>\ConsoleApplication1.exe</Item>
<Item>\ConsoleApplication1.exe.config</Item>
<Item>\ConsoleApplication1.pdb</Item>
<Item>\ConsoleApplication1.vshost.exe</Item>
<Item>\ConsoleApplication1.vshost.exe.config</Item>
<Item>..folder1\gold.dll</Item>
<Item>..images\exit.png</Item>
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
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>