XmlSerializer to have attribute and prefix in XML file - c#

I could get this XML file from C# class with XmlSerializer.
<?xml version="1.0" encoding="utf-8"?>
<Component xmlns:spirit="b" xmlns:chrec="a" MovieName="0" BlocksNotCovered="0">
<ClassInfoList>
<chrec:string>hello</chrec:string>
<chrec:string>world</chrec:string>
</ClassInfoList>
<moduleName />
<world>
<x>10</x>
<y>20</y>
</world>
</Component>
How can I add prefix namespaces for chrec and spriti? For example, how can I get this XML file?
<?xml version="1.0" encoding="utf-8"?>
<spirit:Component xmlns:spirit="b" xmlns:chrec="a" MovieName="0" BlocksNotCovered="0">
<spirit:ClassInfoList>
<chrec:string>hello</chrec:string>
<chrec:string>world</chrec:string>
</spirit:ClassInfoList>
<spirit:moduleName />
<chrec:world>
<chrec:x>10</chrec:x>
<chrec:y>20</chrec:y>
</chrec:world>
</spirit:Component>
This is the C# code.
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.Linq;
namespace Coverage
{
public class Hello
{
public int x;
public int y;
public Hello()
{
x = 10;
y = 20;
}
}
public class Component {
[XmlAttribute("MovieName")]
public int MovieName;
[XmlAttribute("BlocksNotCovered")]
public int BlocksNotCovered;
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces ns;
public List<string> ClassInfoList;
public string moduleName;
public Hello world;
public Component()
{
ClassInfoList = new List<string>() {"hello", "world"};
MovieName = 0;
BlocksNotCovered = 0;
moduleName = "";
world = new Hello();
}
}
class Cov2xml
{
static void Main(string[] args)
{
string xmlFileName = "perf.xml";
Component report = new Component();
TextWriter writeFileStream = new StreamWriter(xmlFileName);
report.ns = new XmlSerializerNamespaces();
report.ns.Add("chrec","a");
report.ns.Add("spirit","b");
var ser = new XmlSerializer(typeof(Component));
ser.Serialize(writeFileStream, report, report.ns);
writeFileStream.Close();
}
}
}

Thanks to the link from competent_tech, I could figure out the way to do it.
How to set the prefix namespace?
You can use XmlRootAttribute, the important thing is that the names space is the namespace, not the namespace name. In the example, it should be "b" not "chrec".
[XmlRootAttribute("Component", Namespace="http://namespace", IsNullable = false)]
public class Component {
How to set the prefix namespace for a specific element?
You can use XmlElement just before the variable.
[XmlElement("xyz", Namespace="http://www.namespace", IsNullable = false)]
int x;
And you'll get this.
<?xml version="1.0" encoding="utf-8"?>
<chrec:Component xmlns:spirit="http:..." MovieName="0" BlocksNotCovered="0" xmlns:chrec="...">
<chrec:ClassInfoList>
<chrec:string>hello</chrec:string>
<chrec:string>world</chrec:string>
</chrec:ClassInfoList>
<chrec:moduleName />
<chrec:world>
<spirit:xyz>10</spirit:xyz>
<chrec:y>20</chrec:y>
</chrec:world>
</chrec:Component>

Related

How to return an XML element value from a Descendant when passing in another element value from that Descendant

I am new to working with LINQ to XML, but I can see how it could be helpful to my current problem. I want a method that you pass in an XML Document and an Element value, the method would then return a different Element Value from the same Descendant. For example if I provided a "StationName" I would like to know what "ScannerType" belongs to that "StationName"
Here is my XML
<?xml version="1.0" encoding="utf-8" ?>
<stations>
<station>
<stationName>CH3CTRM1</stationName>
<scannerType>GE LightSpeed VCT</scannerType>
<scannerID>COL02</scannerID>
<siteName>CUMC</siteName>
<inspDose>180</inspDose>
<expDose>100</expDose>
<kernel>STANDARD</kernel>
</station>
<station>
<stationName>CTAWP75515</stationName>
<scannerType>SIEMENS Force</scannerType>
<scannerID>UIA07</scannerID>
<siteName>Iowa</siteName>
<inspDose>careDose</inspDose>
<expDose>careDose</expDose>
<kernel>Qr40 5</kernel>
</station>
<station>
<stationName>JHEB_CT06N_JHOC2</stationName>
<scannerType>SIEMENS Force</scannerType>
<scannerID>JHU04</scannerID>
<siteName>JHU</siteName>
<inspDose>careDose</inspDose>
<expDose>careDose</expDose>
<kernel>Qr40 5</kernel>
</station>
</stations>
Here are the methods that are currently in question
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;
namespace ManualPhantomProcessor.XMLParser
{
class SearchXML
{
public string filename = "SiteData.xml";
public string currentDirectory = Directory.GetCurrentDirectory();
public XDocument LoadXML()
{
string siteDataFilePath = Path.Combine(currentDirectory, filename);
XDocument siteData = XDocument.Load(siteDataFilePath);
return siteData;
}
public IEnumerable<string> GetScannerModel(XDocument xmlDocument, string stationName)
{
var query = xmlDocument.Descendants("station")
.Where(s => s.Element("stationName").Value == stationName)
.Select(s => s.Element("scannerType").Value)
.Distinct();
return query;
}
}
}
Here is my Programs.cs file
using ManualPhantomProcessor.XMLParser;
using System;
using System.Collections.Generic;
using System.Xml.Linq;
namespace ManualPhantomProcessor
{
class Program
{
static void Main(string[] args)
{
SearchXML searchXML = new SearchXML();
XDocument siteData = searchXML.LoadXML();
IEnumerable<string> data = searchXML.GetScannerModel(siteData, "CH3CTRM1");
Console.WriteLine(data);
}
}
}
I should be a simple console application, but it seem like no matter what I try I keep getting a null value when I expect the scannerType value from the XML document that corresponds with the station name "CH3CTRM1"
the application doesn't crash but in my console I get the following:
System.Linq.Enumerable+DistinctIterator`1[System.String]
Could explain what I am doing incorrectly?
Your code is good, the problem is here Console.WriteLine(data); the WriteLine take string like a parameter not a list of string. to display the station names use a loop, like the following code :
foreach(string stationName in data)
{
Console.WriteLine(stationName);
}
The documentation of WriteLine
i hope that will help you fix the issue.
What you're seeing is the string form of the IEnumerable<string> returned by GetScannerModel().
There are two possibilities:
Only one scanner model is expected to be found (because a station name is expected
to be unique).
Any number of scanner models can be found.
In the first case, change GetScannerModel() to return a string and have it do soemthing like return query.FirstOrDefault(); (or .First() if you want an exception if no match was found). Your client program then remains unchanged.
In the second case, #Sajid's answer applies - you need to enumerate the IEnumerable in some way, for example through foreach.
Use a dictionary :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
List<Station> stations = doc.Descendants("station").Select(x => new Station
{
stationName = (string)x.Element("stationName"),
scannerType = (string)x.Element("scannerType"),
scannerID = (string)x.Element("scannerID"),
siteName = (string)x.Element("siteName"),
inspDose = (string)x.Element("inspDose"),
expDose = (string)x.Element("expDose"),
kernel = (string)x.Element("kernel")
}).ToList();
Dictionary<string, Station> dict = stations
.GroupBy(x => x.stationName, y => y)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
}
}
public class Station
{
public string stationName {get;set;}
public string scannerType {get;set;}
public string scannerID {get;set;}
public string siteName {get;set;}
public string inspDose {get;set;}
public string expDose {get;set;}
public string kernel { get; set; }
}
}

XML Serializing list of objects containing list of objects

My object structure is similar to the simplified code below. Please note that both Countries and Cars need to be classes, I can't use string list/array due to code not included in sample. I want to XML serialize and later deserialize the objects.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Serialization;
namespace XMLapp
{
public partial class Form1 : Form
{
List<Countries> Country = new List<Countries>();
List<string> cars = new List<string>();
public Form1()
{
InitializeComponent();
cars.Add("Audi");
cars.Add("BMW");
cars.Add("Mercedes");
addCountry("Germany", cars);
cars.Clear();
cars.Add("Ford");
cars.Add("Chevrolet");
cars.Add("Jeep");
addCountry("USA", cars);
TestXmlSerialize();
Console.WriteLine("Generated list");
}
void TestXmlSerialize()
{
XmlSerializer x = new XmlSerializer(Country.GetType());
x.Serialize(Console.Out, Country);
}
void addCountry(string name, List<string> cars)
{
Countries newCountry = new Countries();
newCountry.Name = name;
newCountry.AddCar(cars);
Country.Add(newCountry);
}
}
public class Countries
{
public string Name { get; set; }
List<Cars> car = new List<Cars>();
public void AddCar(List<string> cars)
{
for (int i = 0; i < cars.Count; i++)
{
Cars newCar = new Cars();
newCar.brand = cars[i];
car.Add(newCar);
}
}
class Cars
{
public string brand;
}
}
}
This generates following output:
<?xml version="1.0" encoding="IBM437"?>
<ArrayOfCountries xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Countries>
<Name>Germany</Name>
</Countries>
<Countries>
<Name>USA</Name>
</Countries>
</ArrayOfCountries>
However, I expected something along the lines of
<Countries>
<Name>Germany</Name>
<ArrayOfCars>
<Brand>Audi</Brand>
<Brand>BMW</Brand>
<Brand>Mercedes</Brand>
</ArrayOfCountries>
</Countries>
I can see that the car brands are stored properly in the Locals & Autos window, but how do I include them in the serialization?
XmlSerializer only serializes public fields and properties. You need to make the 'car' field and the class 'Cars' public.
It won't produce the exact xml layout that you posted in your question, but it will let you serialize and deserialize the object.

Correctly parsing an XML file in C# [duplicate]

This question already has answers here:
How does one parse XML files? [closed]
(12 answers)
Closed 7 years ago.
I'm trying to read a given file saved in xml, but I'm getting the error "Object reference not set to an instance of an object."
Edit: I cannot use any kind of serialization for this.
Easiest approach you can have for such case is using XmlSerializer. That is not the only approach you can do with .net, as there are XmlReader, XmlTextReader and XDocument to help you with that but XmlSerializer allow you to easily convert data structure to xml and back. Here is an example:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
namespace TestXmlSerializer
{
class Program
{
static void Main(string[] args)
{
var g = new Group
{
Name="g2",
Keys = new[] {
new Key { Username="a" },
new Key { Password="b" }
}
};
Group g2;
var xs = new XmlSerializer(typeof(Group));
var s = string.Empty;
using (var tw = new StringWriter()) {
using (var xw = XmlWriter.Create(tw))
xs.Serialize(xw, g);
s = tw.ToString();
}
Console.WriteLine(s);
using (var ms = new StringReader(s))
{
using (var xw = XmlReader.Create(ms))
g2 = xs.Deserialize(xw) as Group;
}
Console.WriteLine(g2.Name);
}
}
[Serializable]
public class Key
{
[XmlAttribute]
public string Title;
[XmlAttribute]
public string Username;
[XmlAttribute]
public string Password;
[XmlAttribute]
public string Url;
[XmlAttribute]
public string Notes;
}
[Serializable]
public class Group
{
[XmlAttribute]
public string Name;
[XmlElement]
public Key[] Keys;
}
}

C# XML to Listbox Help

I have XML that is being returned back from a rest service WCF. The following is an example of the XML
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">
<catalog version="1.1"><dataset id="354" name="Mariano - Ship Drift" description="Global Currents, Static" datatype="currents" rank="5" saropsrank="4" format="netcdf" starttime="1980-01-01T00:00:00" endtime="2019-01-01T00:00:00" extentleft="-180.0000" extentbottom="-90.0000" extentright="180.0000" extenttop="90.0000" source="STATIC" wmslayeridstr="MARIANO_currents" confidence="L" directionfrom="no" image="ne_ndbc.jpg" />
</catalog>
</string>
I need to get the value from id, name, description, etc... and put it into a list or a listbox.
WebResponse response = restWebRequest.GetResponse();
Stream responseStream = response.GetResponseStream();
Reponse stream is the stream that holds the XML.
Any ideas?
XDocument doc = XDocument.Load(responseStream);
var elem = doc.Descendants().FirstOrDefault(el => el.Name.LocalName == "dataset");
if(elem != null)
{
var attID = elem.Attribute("id");
if(attID != null)
Console.WriteLine(attID.Value);
}
OR
You could directly get the IEnumerable with an anonymous type:
XDocument doc = XDocument.Parse(xml);
var values = doc.Descendants("dataset")
.Select(el => new { id = el.Attribute("id").Value,
name = el.Attribute("name").Value
}
);
Here's another approach: (I tested your XML by loading it from a file.)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.IO;
namespace delete4
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Load();
}
void Load()
{
var stream = new FileStream("c:\\pj\\data.txt", FileMode.Open);
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "string";
xRoot.IsNullable = true;
xRoot.Namespace = "http://schemas.microsoft.com/2003/10/Serialization/";
XmlSerializer s = new XmlSerializer(typeof(sstring), xRoot);
var o = s.Deserialize(stream) as sstring; // o is your loaded object
stream.Close();
}
[ XmlRoot("string"), XmlType("string")]
public class sstring
{
public Catalog catalog;
}
public class Catalog
{
public Dataset dataset;
}
public class Dataset
{
[XmlAttribute("name")]
public string Name;
[XmlAttribute("id")]
public string ID;
[XmlAttribute("description")]
public string Description;
}
}
}

Export a collection of objects (which in turn contains a collection object) to xml

I have a data object class which stores several properties. One is folder, and another is a string[] of all of the files in that array.
What I need to do is write this out to xml, like follows:
<X>
<a>dir</a>
<b>file</f>
So all of the files (there is a string[] array per data object), is nested below the directory field.
Is this easily possible? Or is there an external library which can do this easily for me?
Thanks
you mean something like this:
var myxml = new XElement(yourObj.FolderName);
myxml.Add(new XElement("Files",yourObj.Files.Select(x => new XElement("File",x)));
Use Xml Serializer to do the work for you?
using System.Linq;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.IO;
using System;
namespace NS
{
public class Data
{
public class Nested
{
public string The { get; set; }
public string[] stuff = {"lazy Cow Jumped Over", "The", "Moon"};
}
public List<Nested> Items;
}
static class Helper
{
public static string ToXml<T>(this T obj) where T:class, new()
{
if (null==obj) return null;
using (var mem = new MemoryStream())
{
var ser = new XmlSerializer(typeof(T));
ser.Serialize(mem, obj);
return System.Text.Encoding.UTF8.GetString(mem.ToArray());
}
}
public static T FromXml<T>(this string xml) where T: new()
{
using (var mem = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(xml)))
{
var ser = new XmlSerializer(typeof(T));
return (T) ser.Deserialize(mem);
}
}
}
class Program
{
public static void Main(string[] args)
{
var data = new Data { Items = new List<Data.Nested> { new Data.Nested {The="1"} } };
Console.WriteLine(data.ToXml());
var clone = data.ToXml().FromXml<Data>();
Console.WriteLine("Deserialized: {0}", !ReferenceEquals(data, clone));
Console.WriteLine("Identical: {0}", Equals(data.ToXml(), clone.ToXml()));
}
}
}
Will output
<?xml version="1.0" encoding="utf-8"?>
<Data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Items>
<Nested>
<stuff>
<string>lazy Cow Jumped Over</string>
<string>The</string>
<string>Moon</string>
</stuff>
<The>1</The>
</Nested>
</Items>
</Data>
Deserialized: True
Identical: True
There are some cornercases and gotchas especially when working with existing XSD, but this is all very well-trod and documented elsewhere.

Categories

Resources