XML deserialize iso 20022 pain.001.001.03 from xsd using c# - c#

I want to get an object from an xml file. In my example I am using iso 2002 pain.001.001.03
I have downloaded the schema from
pain.001.001.03.xsd
and the xml file from
pain.001.001.03.xml
I have validated my xml against the xsd using this tool
Validate XML
I have generated a class using xsd
and I am using the code below in order to deserialize
XmlSerializer ser = new XmlSerializer(typeof(CustomerCreditTransferInitiationV03), new XmlRootAttribute
{
ElementName = "Document",
Namespace = "urn:iso:std:iso:20022:tech:xsd:pain.001.001.03",
});
FileStream myFileStream = new FileStream("C:\\001.001.03\\pain.001.001.03.xml", FileMode.Open);
CustomerCreditTransferInitiationV03 myObject = (CustomerCreditTransferInitiationV03) ser.Deserialize(myFileStream);
The code return null values but my xml has values

<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03">
<CstmrCdtTrfInitn>
The root element is an Document, and not a CstmrCdtTrfInitn :
var serializer = new XmlSerializer(typeof(Document));
using (var file = File.OpenRead(path))
{
var document = (Document)serializer.Deserialize(file);
var transfer = document.CstmrCdtTrfInitn;
}

Related

XML error during deserialize

I have problem when I'm trying to deserialize an XML to object. My XML look like:
<?xml version="1.0" encoding="utf-16"?>
<Products
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<AllProducts>
<Product>
<ID>8</ID>
<GID>51280</GID>
<Kod>RNIKAKC1.6</Kod>
<Name>SB-800</Name>
<Ean>0018208048014</Ean>
<CommodityGroup>
<ID>86</ID>
<Name>AKCESORIA FOTO</Name>
<Path>
<Category>
<ID>60798</ID>
<Name>ARCHIWALNE</Name>
</Category>
</Path>
</CommodityGroup>
</Product>
....
Next products
...
My method code:
var MemoryStream = APIAccess.DownloadFileToStream("example.xml", "exampleContainer");
using (MemoryStream)
{
MemoryStream.Position = 0;
using (StreamReader StreamReader = new StreamReader(MemoryStream))
{
XmlSerializer serializer = new XmlSerializer(typeof(CommodityGroup));
var products = serializer.Deserialize(StreamReader);
}
}
Method DownloadFileToStream is working good, because it is useful in other classes.
I'm geting error:
InvalidOperationException: Products xmlns='' was not expected.
I want to create object of a Node CommodityGroup. I've created class selecting this node, coping it and pasting in the new class like Paste Special -> XML
Attributes of this class looks like:
[Serializable()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[XmlTypeAttribute(AnonymousType = true)]
[XmlRootAttribute(Namespace = "CommodityGroup", IsNullable = false)]
I don't know to fix it. When I'm adding into XML Serializer param new XmlRootAttribute("Products"), I'm getting "0" values.
Do you have any suggestions?
If you want to deserialize only part of an xml document, you should skip unnecessary nodes.
Do it using XmlReader.
using (StreamReader StreamReader = new StreamReader(MemoryStream))
using (var xmlReader = XmlReader.Create(StreamReader))
{
xmlReader.ReadToFollowing("CommodityGroup");
XmlSerializer serializer = new XmlSerializer(typeof(CommodityGroup));
var commodityGroup = (CommodityGroup)serializer.Deserialize(xmlReader);
}

Most efficient way to determine how class use to Deserialize XML

I have many .xsd files for many xml schemas
example
XML 1.0 - xml_1_0.xml
<?xml version="1.0" encoding="UTF-8"?>
<cars version="1.00">
<car>Honda</car>
<car>Ferrari</car>
</cars>
XML 2.0 - xml_2_0.xml
<?xml version="1.0" encoding="UTF-8"?>
<cars version="2.00">
<car>
<name>Honda</name>
<color>White</color>
</car>
<car>
<name>Honda</name>
<color>Red</color>
</car>
</cars>
I create my classes from .xsd like this
xsd.exe cars_1_0.xsd /c
xsd.exe cars_2_0.xsd /c
And Deserialize like this:
foreach(string file in files) {
XmlDocument doc = new XmlDocument();
doc.Load(file);
string version = doc.SelectSingleNode("/Cars/#version").Value;
if(version == "1.00")
{
Stream reader = new FileStream(file, FileMode.Open);
XmlSerializer serializer = new XmlSerializer(typeof(v1.Cars));
v1.Cars XML = new v1.Cars();
XML = (v1.Cars)serializer.Deserialize(reader);
}
else if(version == "2.00")
{
Stream reader = new FileStream(file, FileMode.Open);
XmlSerializer serializer = new XmlSerializer(typeof(v2.Cars));
v2.Cars XML = new v2.Cars();
XML = (v2.Cars)serializer.Deserialize(reader);
}
}
Does anyone know a better way to do this, or have a better performance?
You have several options, depending on how far you want to take this. One fairly non invasive option would be to not use XmlDocument and avoid loading the stream more than once. For example, your existing code could be simplified/streamlined to :
foreach (string file in files)
{
using (var stream = new FileStream(file, FileMode.Open))
{
var settings = new XmlReaderSettings();
settings.CloseInput = false;
string version = "";
using (var xmlReader = XmlReader.Create(stream))
{
if (xmlReader.ReadToFollowing("Cars"))
{
version = xmlReader.GetAttribute("version");
}
else
{
throw new XmlException("Could not get 'version' attribute of 'Cars' root element!");
}
}
stream.Position = 0;
if (version == "1.00")
{
XmlSerializer serializer = new XmlSerializer(typeof(v1.Cars));
v1.Cars XML = new v1.Cars();
XML = (v1.Cars)serializer.Deserialize(stream);
}
else if (version == "2.00")
{
XmlSerializer serializer = new XmlSerializer(typeof(v2.Cars));
v2.Cars XML = new v2.Cars();
XML = (v2.Cars)serializer.Deserialize(stream);
}
}
}
Since you're just reading off the root element, you might even be able to get away with deserializing from the XmlReader and not have to reset the position on the FileStream.
This avoids the overhead of loading the entire file twice (once for XmlDocument, then again for XmlSerializer) - and particularly avoids the memory overhead of creating a DOM for each document.
A more nuclear option would be implementing IXmlSerializable on a set of custom classes, which would have custom logic in the ReadXml methods to parse the version attribute and instantiate the correct child type(s) - e.g. a CarCollection class that has a List<Car> property, where Car is an abstract class that has CarV1 and CarV2 as descendants. This would be about as efficient as you could get (and offer very fine grained control over your class hierarchy design), but would eliminate the possibility of using xsd.exe to generate your classes.

Encoding attribute from XML file Declaration turns to lower case when the file is created by a MemoryStream

I have to generate a XML file using "ISO-8859-1" encoding from my Asp.Net Web API application but MemoryStream lowercases the encoding attribute from the generated XML definition to "iso-8859-1".
This method generates a XML file based on a object which has been created by a XSD.
public static MemoryStream GenerateXml<T>(T entity) where T : class
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
//Add an empty namespace and empty value
ns.Add("", "");
var memoryStream = new MemoryStream();
var streamWriter = new StreamWriter(memoryStream, Encoding.GetEncoding("ISO-8859-1"));
var serializer = new XmlSerializer(typeof(T));
serializer.Serialize(streamWriter, entity, ns);
return memoryStream;
}
Then I need to use XDocument to replace the prefix definition of XML elements (Its a prerequisite that all elements should be only named with their own tags). So I had to do this:
public MemoryStream GenerateXmlOpening<T>(T entity) where T : class
{
var xmlMemStream = XmlHelper.GenerateXml(entity);
xmlMemStream.Position = 0;
XDocument doc = XDocument.Load(xmlMemStream, LoadOptions.PreserveWhitespace);
//Removes the namespace declaration as prefix on elements
doc.Descendants().Attributes().Where(a => a.IsNamespaceDeclaration).Remove();
//the memory stream retreived from 'xmlMemStream' is already with "iso-8859-1 in lowercase, so im trying to override it
doc.Declaration.Encoding = "ISO-8859-1";
MemoryStream stream = new MemoryStream();
// when i save the xdoc to the new memorystream, the encoding goes from "ISO-8859-1" to "iso-8859-1" again.
doc.Save(stream);
stream.Position = 0;
return stream;
}
This is the beginning of the returned generated XML file:
<?xml version="1.0" encoding="iso-8859-1"?>
... content
How it's supposed to be:
<?xml version="1.0" encoding="ISO-8859-1"?>
... content
Ps.* Im writing the XML using a MemoryStream because I have to write a .zip file and return a response of all generated XML files within this zip. This .Zip generator receives a list of MemoryStreams.

XML Serializer C# Namespaces Duplicate Issue

I am using XmlSerializer in C# to generate an XML document based on a model. I need to generate the following XML root that contains a duplicate namespace using separate prefixes. Below is what the output should look likeā€¦
<ClinicalDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:hl7-org:v3 CDA_SDTC.xsd"
xmlns="urn:hl7-org:v3"
xmlns:cda="urn:hl7-org:v3"
xmlns:sdtc="urn:hl7-org:sdtc">
However, when I Serialize this, the default entry is removed (which contains the duplicate namespace) and the root is prefixed.
<cda:ClinicalDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sdtc="urn:hl7-org:sdtc" xsi:schemaLocation="http://www.w3.org/2001/XMLSchema-instance" xmlns:cda="urn:hl7-org:v3">
Here is my XmlSerializer code...
var writer = new XmlSerializer(clinicalDocument.GetType(),"urn:hl7-org:v3");
var myNamespace = new XmlSerializerNamespaces();
myNamespace.Add("sdtc", "urn:hl7-org:sdtc");
myNamespace.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");
myNamespace.Add("cda", "urn:hl7-org:v3");
using (var file = new System.IO.StreamWriter(CCDUncOutputPath))
{
writer.Serialize(file, clinicalDocument, myNamespace);
file.Close();
};
writer = null;
GC.Collect();
Does anyone have a fix for this?

Deserialization Xml Document Error

I have a problem when I deserialize the xml into List of Objects. I searched it on the net this morning, but my problem isn't resolved.
Deserialization method
public static List<FileAction> DeSerialization()
{
XmlRootAttribute xRoot=new XmlRootAttribute();
xRoot.ElementName="ArrayOfSerializeClass";
xRoot.IsNullable=true;
XmlSerializer serializer = new XmlSerializer(typeof(List<FileAction>),xRoot);//, new XmlRootAttribute("ArrayOfSerializeClass")
using (Stream streamReader = File.OpenRead(#"C:\serialization\SerializationWithFileWatcher\Output\XmlSerialize.xml"))//FileStream fs =new FileStream(xmlPath,FileMode.Open)
{
using (XmlReader reader = XmlReader.Create(streamReader))
{
int count =0;
List<FileAction> serialList2 = (List<FileAction>)serializer.Deserialize(reader);
return (List<FileAction>)serializer.Deserialize(reader);
}
}
Calling Method
String resultPath = #"C:\serialization\SerializationWithFileWatcher\Output\XmlSerialize.xml";
if (!File.Exists(resultPath))
{
XmlSerializer xs = new XmlSerializer(typeof(List<SerializeClass>));
using (FileStream fileStream = new FileStream(#"C:\serialization\SerializationWithFileWatcher\Output\XmlSerialize.xml", FileMode.Create))
{
xs.Serialize(fileStream, serializeList);//seri
fileStream.Close();
}
Console.WriteLine("Succesfully serialized to XML");
}
else
{
//string path= #"C:\serialization\SerializationWithFileWatcher\Output\XmlSerialize.xml";
DeSerialization();
XmlSerializer xs = new XmlSerializer(typeof(List<SerializeClass>));
FileStream fs = new FileStream(#"C:\serialization\SerializationWithFileWatcher\Output\XmlSerialize.xml", FileMode.Append, FileAccess.Write);
using (XmlWriter xwr = XmlWriter.Create(fs))//TextWriter xwr = new StreamWriter
{
xs.Serialize(xwr, serializeList);//seri
//fs.Close();
}
Console.WriteLine("Succesfully serialized to XML");
}
return serializeList;
The reason why I am calling it here is that I want to add this object again to the xml file.
THe error is that here is an error in XML document (15,27).
My Xml structure
<?xml version="1.0"?>
<ArrayOfSerializeClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SerializeClass>
<creationTime>2013-11-25T09:53:25.3325289+05:30</creationTime>
<fileAction>Renamed</fileAction>
<Properties>
<FileAttributes fileName="validate json.txt">
<fileSize>307</fileSize>
<extension>.txt</extension>
<lastAccessTime>2013-11-25T09:53:25.3325289+05:30</lastAccessTime
<fullPath>C:\serialization\SerializationWithFileWatcher\SerializationWithFileWatcherProj\validate json.txt</fullPath>
</FileAttributes>
</Properties>
</SerializeClass>
</ArrayOfSerializeClass>
What I understand from the code above is that you are trying to extend the current XML, by first reading it as a FileStream and then using an XmlWriter to add some more content to it.
If my understanding is correct, then you are trying to write to the end of an existing XML file, which is not allowed since any XML document can have only one root node. In your case, that root node is ArrayOfSerializeClass.
So, in order to successfully achieve your task, you must append your XML within the root node.
Update:
Possible solution here: how to append a xml file in c#?

Categories