I have a class that I am serializing using XmlSerializer. In addition to other properties, I need to add a chunk of pre-built xml to the object. I already asked how to handle that chuck of xml in this post: How to remove empty namespace attribute on manually added xml string when serializing object?
Now I need to add an attribute to the property that contains the xml string. I understand how to add an attribute to a class but not to a property. If I create a new class to hold the attribute, I get an extra hierarchy in my output.
Here is my simplified code:
public class Book
{
public string Title { get; set; }
public string Author { get; set; }
public XmlElement Extension { get; set; }
public Book()
{
}
public void AddExtension()
{
string xmlString = "<AdditionalInfo xmlns=\"http://www.somenamespace.com\">" +
"<SpecialHandling>Some Value</SpecialHandling>" +
"</AdditionalInfo>";
this.Extension = GetElement(xmlString);
}
public static XmlElement GetElement(string xml)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
return doc.DocumentElement;
}
}
static void Main(string[] args)
{
TestSerialization p = new TestSerialization();
Book bookOne = new Book();
bookOne.Title = "How to Fix Code";
bookOne.Author = "Dee Bugger";
bookOne.AddExtension();
System.Xml.Serialization.XmlSerializer serializer = new XmlSerializer(typeof(Book), "http://www.somenamespace.com");
using (var writer = new StreamWriter("C:\\BookReport.xml"))
using (var xmlWriter = XmlWriter.Create(writer, new XmlWriterSettings { Indent = true }))
{
serializer.Serialize(xmlWriter, bookOne);
}
}
It generates the following output:
<?xml version="1.0" encoding="utf-8"?>
<Book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.somenamespace.com">
<Title>How to Fix Code</Title>
<Author>Dee Bugger</Author>
<Extension>
<AdditionalInfo xmlns="http://www.somenamespace.com">
<SpecialHandling>Some Value</SpecialHandling>
</AdditionalInfo>
</Extension>
</Book>
Now I need to add an attribute to Extension to make the Extension output look like:
...
<Extension Modifier="ABC">
<AdditionalInfo xmlns="http://www.somenamespace.com">
<SpecialHandling>Some Value</SpecialHandling>
</AdditionalInfo>
</Extension>
Is there a way to change the Book class to do this? I tried to create an Extension class to hold the Modifier attribute and the XmlElement of the xml string but that resulted in an extra level:
public class Extension
{
[XmlAttribute]
public string Modifier { get; set; }
[XmlElementAttribute("Extension")]
public XmlElement ExtensionAsElement { get; set; }
public Extension()
{
}
public Extension(XmlElement extensionAsElement)
{
this.Modifier = "ABC";
this.ExtensionAsElement = extensionAsElement;
}
}
public class Book
{
public string Title { get; set; }
public string Author { get; set; }
[XmlElementAttribute("Extension")]
public Extension ExtensionObj { get; set; }
public Book()
{
}
public void AddExtension()
{
string xmlString = "<AdditionalInfo xmlns=\"http://www.somenamespace.com\">" +
"<SpecialHandling>Some Value</SpecialHandling>" +
"</AdditionalInfo>";
this.ExtensionObj = new Extension(GetElement(xmlString));
}
public static XmlElement GetElement(string xml)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
return doc.DocumentElement;
}
}
<?xml version="1.0" encoding="utf-8"?>
<Book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.somenamespace.com">
<Title>How to Fix Code</Title>
<Author>Dee Bugger</Author>
<Extension Modifier="ABC">
<Extension>
<AdditionalInfo xmlns="http://www.somenamespace.com">
<SpecialHandling>Some Value</SpecialHandling>
</AdditionalInfo>
</Extension>
</Extension>
</Book>
Note: this is an overly simplified example of my code, the Book class is not my root. I only need to serialize, not deserialize.
You can use [XmlAnyElement("Extension")]
to specify that your Extension
property should be inserted as-is into the XML stream as the element <Extension>
itself, rather than as a child of an element of that name. Having done so, you will be able to set attributes on the element itself using SetAttribute()
and GetAttribute()
.
Thus your Book
class becomes something like:
public class Book
{
public string Title { get; set; }
public string Author { get; set; }
[XmlAnyElement("Extension")]
public XmlElement Extension { get; set; }
public Book()
{
this.Extension = new XmlDocument().CreateElement("Extension");
}
public Book AddExtension()
{
string innerXmlString = "<AdditionalInfo xmlns=\"http://www.somenamespace.com\">" +
"<SpecialHandling>Some Value</SpecialHandling>" +
"</AdditionalInfo>";
if (Extension == null)
// Since Extension is marked with [XmlAnyElement("Extension")], its value must
// be an XmlElement named "Extension". Its InnerXml can be anything.
Extension = new XmlDocument().CreateElement("Extension");
Extension.InnerXml = innerXmlString;
return this;
}
const string ModifierName = "Modifier";
[XmlIgnore]
public string Modifier
{
get
{
if (Extension == null)
return null;
return Extension.GetAttribute(ModifierName);
}
set
{
if (Extension == null)
AddExtension();
if (value == null)
Extension.RemoveAttribute(ModifierName);
else
Extension.SetAttribute(ModifierName, value);
}
}
}
And creating XML from the following:
var bookOne = new Book { Title = "How to Fix Code", Author = "Dee Bugger", Modifier = "AAA" }
.AddExtension();
Produces the result:
<Book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Title>How to Fix Code</Title> <Author>Dee Bugger</Author> <Extension Modifier="AAA"> <AdditionalInfo xmlns="http://www.somenamespace.com"> <SpecialHandling>Some Value</SpecialHandling> </AdditionalInfo> </Extension> </Book>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.