问题
I am using C# + VSTS2008 + .Net 3.0 to do XML serialization. The code works fine. Here below is my code and current serialized XML results.
Now I want to add two additional layers to the output XML file. Here is my expected XML results. Any easy way to do this? I am not sure whether NestingLevel could help to do this. I want to find an easy way which does not change the structure of MyClass and MyObject.
Expected XML serialization result,
<?xml version="1.0"?>
<MyClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MyObjectProperty>
<AdditionalLayer1>
<AdditionalLayer2>
<ObjectName>Foo</ObjectName>
</AdditionalLayer1>
</AdditionalLayer2>
</MyObjectProperty>
</MyClass>
Current XML serialization result,
<?xml version="1.0"?>
<MyClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MyObjectProperty>
<ObjectName>Foo</ObjectName>
</MyObjectProperty>
</MyClass>
My current code,
public class MyClass
{
public MyObject MyObjectProperty;
}
public class MyObject
{
public string ObjectName;
}
public class Program
{
static void Main(string[] args)
{
XmlSerializer s = new XmlSerializer(typeof(MyClass));
FileStream fs = new FileStream("foo.xml", FileMode.Create);
MyClass instance = new MyClass();
instance.MyObjectProperty = new MyObject();
instance.MyObjectProperty.ObjectName = "Foo";
s.Serialize(fs, instance);
return;
}
}
回答1:
I want to find an easy way which does not change the structure of MyClass and MyObject.
Frankly, that isn't going to happen. XmlSerializer
(when used simply) follows the structure of the classes / members. So you can't add extra layers without changing the structure.
When used in a bespoke way (IXmlSerializable
), the one thing you can say for sure is that it isn't simple... this is not a fun interface to implement.
My advice: introduce a DTO that mimics your desired format, and shim to that before you serialize.
回答2:
Why do you need these additional two layers?
Is its a business requirement, you should add these two objects to your object model:
public class MyClass
{
public AdditionalLayer1 AdditionalLayer1;
}
public class AdditionalLayer1
{
public AdditionalLayer2 AdditionalLayer2;
}
public class AdditionalLayer2
{
public MyObject MyObjectProperty;
}
public class MyObject
{
public string ObjectName;
}
if its purely because of some compatibility requirements you can either do the thing above, or implement IXmlSerializable on MyClass:
public class MyClass : IXmlSerializable
{
public MyObject MyObjectProperty;
public void WriteXml (XmlWriter writer)
{
//open the two layers
//serialize MyObject
//close the two layers
}
public void ReadXml (XmlReader reader)
{
//read all the layers back, etc
}
public XmlSchema GetSchema()
{
return(null);
}
}
回答3:
You could do a transformation with XSL after serializing and add the "missing" tags.
回答4:
I would suggest serializing out to a MemoryStream
instead of a FileStream
and then loading the XML into an XmlDocument
, then using the methods of that class to insert the extra nodes you want. After that, you can save it out.
回答5:
I did exactly this only recently and didn't find overriding the IXmlSerializable interface at all difficult or complicated. Serialize/deserialize as normal but for the class that contains the sub-class which you need to wrap in extra tags derive from IXmlSerializable:
class ContainingClass : IXmlSerializable
{
...
#region IXmlSerializable Members
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
**reader.ReadStartElement("Equipment");**
XmlSerializer ser = new XmlSerializer(typeof(Host));
while (reader.NodeType != XmlNodeType.EndElement)
{
Host newHost = new Host();
newHost.Name = (string) ser.Deserialize(reader);
_hosts.Add(newHost);
reader.Read();
}
// Read the node to its end.
// Next call of the reader methods will crash if not called.
**reader.ReadEndElement(); // "Equipment"**
}
public void WriteXml(XmlWriter writer)
{
XmlSerializer ser = new XmlSerializer(typeof(Host));
**writer.WriteStartElement("Equipment");**
foreach (Host host in this._hosts)
{
ser.Serialize(writer, host);
}
**writer.WriteEndElement();**
}
#endregion
All I do here is to wrap the de/serialization of the lower level objects. Here I'm wrapping an extra tag "Equipment" around all the Hosts in a collection in this class. You could add as many tags as you like here as long as you close each one you start.
NOTE: Bold is showing as ** text ** - just make sure you get rid of the double asterisks :)
来源:https://stackoverflow.com/questions/1226664/wrapping-serialized-properties-in-additional-elements-with-net-xml-serializatio