Reputation: 1
I have two identical XML files containing info about persons.they differ only in their tag names. for e.g. for the first, i have
<name>
<surname>
<address>...
and in the second one, i have
<name_person>
<surname_person>
<address_person>
i need to "de-serialize" them into two separate objects in vb.net. i have only one class with properties Name,Surname,Address.. is it possible to use just this one class for the second XML file too?because the latter's tag names don't match.
thanks
Upvotes: 0
Views: 3004
Reputation: 3260
The easiest thing, I think would be to control the deserialization separately. I looked for finding aliases for the XmlElement attribute, but I didn't see anything like that. Furthermore, when you serialize the objects again, how would it know which tags it is supposed to use.
Once you have deserialized from your second object, it would not be that hard in code to create new instances of your first class and copy the properties over.
You can also do something like this, which makes one class that is great at reading, but you shouldn't use this class for writing or it will write all the properties.
VB.NET
<XmlRoot("PersonList")> _
Public Class PersonList
<XmlElement("person")> _
Public Property People() As Person()
Get
Return m_People
End Get
Set
m_People = Value
End Set
End Property
Private m_People As Person()
End Class
Public Class Person
Private _name As String
<XmlElement("name")> _
Public Property Name() As String
Get
Return _name
End Get
Set
_name = value
End Set
End Property
<XmlElement("name_person")> _
Public Property NamePerson() As String
Get
Return _name
End Get
Set
_name = value
End Set
End Property
End Class
C#
[XmlRoot("PersonList")]
public class PersonList {
[XmlElement("person")]
public Person[] People { get; set; }
}
public class Person {
private String _name;
[XmlElement("name")]
public String Name {get{return _name;} set{_name = value;}}
[XmlElement("name_person")]
public String NamePerson {get{return _name;} set{_name = value;}}
}
reference: XML deserialize: different xml schema maps to the same C# class
Alternately, it looks like you can use your original class, but then handle the XmlSerializer.UnknownElement event.
(untested) VB.Net
Private Shared Sub serializer_UnknownElement(sender As Object, e As XmlElementEventArgs)
Dim target = DirectCast(e.ObjectBeingDeserialized, Person)
If e.Element.Name = "name_person" Then
target.Name = e.Element.InnerText
End If
End Sub
C#
static void serializer_UnknownElement(object sender, XmlElementEventArgs e)
{
var target = (Person) e.ObjectBeingDeserialized;
if( e.Element.Name == "name_person")
{
target.Name = e.Element.InnerText;
}
}
But again, this won't let you save back to the old format, only load from your old format into your new class.
reference: http://weblogs.asp.net/psteele/archive/2011/01/31/xml-serialization-and-the-obsolete-attribute.aspx
reference: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.unknownelement.aspx
Upvotes: 1
Reputation: 1555
You could use XSLT to update the second document to match the element names you're expecting. That way, you don't have to handle the different element names in the code.
Transform the second document using XSLT, something like:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//name_person">
<name>
<xsl:apply-templates select="@*|node()" />
</name>
</xsl:template>
<xsl:template match="//surname_person">
<surname>
<xsl:apply-templates select="@*|node()" />
</surname>
</xsl:template>
<xsl:template match="//address_person">
<address>
<xsl:apply-templates select="@*|node()" />
</address>
</xsl:template>
</xsl:stylesheet>
It apply this programatically to your document, in C#, you could do:
XslCompiledTransformtransform = new XslCompiledTransform();
transorm.Load("update.xsl");
transorm.Transform("source.xml","new.xml");
In VB:
Dim transform As XslTransform
transform = New XslTransform()
transform .Load("update.xsl")
transform .Transform("source.xml", "new.xml")
The result will then be the element names will match across both documents, and you could then run your deserializer on the XML without having to worry about handling mismatched element names.
Upvotes: 0
Reputation: 28839
You should be able to use a SerializationBinder where you can specify (remap) the type of the element being deserialized.
Upvotes: 0