0

I'm troubleshooting some old existing .Net 4.6.1 code that is XML serializing this class:

public class Orders
{
    private int _pagenumber = 0;

    [XmlAttribute]
    public int pages
    {
        get { return _pagenumber; }
        set { _pagenumber = value; }
    }

    [XmlText]
    public string OrdersXml { get; set; }
}

The OrdersXml string contains a block of already-XML-serialized Order objects (i.e. XML text like: "<Order><OrderId>1</OrderId>...</Order><Order>...</Order>..."). (They are being XML serialized elsewhere for a variety of reasons and this is not subject to redesign.)

The intent is to include that block of XML verbatim in the serialization of this Orders object - in other words, as if string OrdersXml was instead an Orders[] OrdersXML being serialized as part of the Orders object, ending up like: <Orders pages="6"><Order><OrderID>123456</OrderID>...</Order>...</Orders>

But that's not happening. The XML in the OrdersXml property is being serialized as XML-escaped plain text, and it's coming out "<Orders pages="6">&lt;Order&gt;&lt;OrderID&gt;2&lt;/OrderID&gt;..." - the code is doing post-serialization cleanup to reverse that, and it's coming out useably correct in most cases. I'd rather it serialize correctly in the first place...

I've tried using [XmlText(typeof(string))] instead but that didn't help.

Is the XmlSerializer ignoring the [XmlText] attribute on OrdersXml, or is that not what [XmlText] is intended to do?

What is the "correct" best-practice way to composite XML like this?

  • The only way you would get <Order><OrderID>2</OrderID&gt is if you attached the XML to an HTTP Request. – jdweng Mar 23 '21 at 18:17
  • Wrap that serialized string of XML in a CDATA section so your XML document knows not to mess with it. – Rex Henderson Mar 23 '21 at 18:17
  • 1
    Rather than `[XmlText]` which is for character data, use an [`[XmlAnyElement] public XElement OrdersXml { get; set; }`](https://learn.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlanyelementattribute) property as shown in [this answer](https://stackoverflow.com/a/255469/3744182) to [Serializing Name/Value Pairs in a Custom Object via Web Service](https://stackoverflow.com/q/255400/3744182) and also [this one](https://stackoverflow.com/a/38346726/3744182) to [C#: Best way to have XML element name from generic type name](https://stackoverflow.com/q/38344516/3744182). – dbc Mar 23 '21 at 18:18
  • Or use `List` if you might have more than one as shown in [this answer](https://stackoverflow.com/a/35586061/3744182) to [Deserialize dynamic XML](https://stackoverflow.com/q/35555278/3744182). Do those answers answer your question also? Or might your `OrdersXml` sometimes contain character data or mixed content? – dbc Mar 23 '21 at 18:25
  • jdweng: Nope, I am looking at the output string of the XML serializer in the debugger immediately after serialization, nothing else has touched it. rex: I cannot use CDATA as the string is fragmentary XML content that is supposed to be an integral part of the final serialized XML document, not a block of text data to be carried by the document. dbc: OrdersXML is *always* a string containing XML that has been serialized elsewhere and is to be included verbatim in the final serialized document. The "verbatim" part is what isn't working. I will look into your suggestions, thanks. – John Hardin Mar 24 '21 at 01:56
  • @dbc: all of those examples are targeted at scenarios that are more complicated than what I have - they involve ways to get more-or-less complex classes to serialize with various class properties intact. The problem I'm trying to solve here is very simple: how to emit a string property that contains properly-formed XML markup into the serialization of the object *without* it emitting an extra XML tag for that property and *without* it making *any* changes to the string. Think something like an [XmlRaw] attribute that just dumps that property's content into the XML output stream unmodified. – John Hardin Mar 24 '21 at 15:05
  • @JohnHardin - right, but [there is no `[XmlRaw]`](https://learn.microsoft.com/en-us/dotnet/standard/serialization/attributes-that-control-xml-serialization). Your options are `[XmlAnyElement]` or manually serializing the `Orders` class by implementing [`IXmlSerializable`](https://stackoverflow.com/q/279534/3744182). By the way, is `OrdersXml` well-formed XML (i.e. with a single root element) or a well-formed XML fragment (i.e. with multiple root elements)? – dbc Mar 24 '21 at 15:09
  • Hmmm, If `Orders` really is that simple, implementing `IXmlSerializable` looks viable. Want a solution that does that? – dbc Mar 24 '21 at 15:13
  • There's a demo implementation of `IXmlSerializable` here: https://dotnetfiddle.net/V8TEui. Even for simple models, `IXmlSerializable` is fussy to implement. – dbc Mar 24 '21 at 16:30
  • @dbc - Yeah the `[XmlRaw]` is me wishing hard... The `OrdersXML` string will always be a well-formed XML fragment of the form "`.........`" for one or more order objects serialized elsewhere. In this case, implementing `IXmlSerializable` is *way* heavier than I feel is justified - what I've done is put a simple text token in the string instead and do `serializedXml.Replace(TOKEN, orderXmlString)` afterwards. It's an ugly hack and I'm not proud of it, but absent some simple attribute that tells the serializer to just emit the string without modification it'll do. – John Hardin Mar 24 '21 at 17:58
  • ...and it's **way** better than the post-serialization cleanup that the code was originally doing. – John Hardin Mar 24 '21 at 17:59
  • What .Net version is being used for all of this? Nevermind I just saw your fiddle....looks like .Net 5 – Rex Henderson Mar 28 '21 at 21:51
  • @rex - The .Net version the app is using is 4.6.1 – John Hardin Mar 29 '21 at 14:38

0 Answers0