Deserialize element value as string although it contains mixed content

雨燕双飞 提交于 2019-12-19 08:09:34

问题


Assuming an XML like this:

<my:Root xmlns:my="http://foo/bar">
    <my:FieldBasic>content</my:FieldBasic>
    <my:FieldComplex>
        <html xml:space="preserve" xmlns="http://www.w3.org/1999/xhtml">
            <div><h1>content</h1></div>
        </html>
    </my:FieldComplex>
<my:Root>

and a class like:

[Serializable]
[XmlType(AnonymousType = true, Namespace = "http://foo/bar")]
[XmlRoot(ElementName = "Root", Namespace = "http://foo/bar", IsNullable = false)]
public class MyRoot
{
    public string FieldBasic { get; set; }
    public string FieldComplex { get; set; }
}

How do I deserialize <my:FieldComplex> to a string within FieldComplex? It fails when it finds the HTML inside. I want to make it give me a string with this content:

<html xml:space="preserve" xmlns="http://www.w3.org/1999/xhtml">
    <div><h1>content</h1></div>
</html>

If I declare FieldComplex as public object FieldComplex (i.e. xsd:anyType) it kinda works and I get a XMLNode[] inside which I can use.

But I need the FieldComplex to be of type string for the serialization as for serialization the XML will not contain HTML, it will be like:

<my:Root xmlns:my="http://foo/bar">
    <my:FieldBasic>content</my:FieldBasic>
    <my:FieldComplex>content</my:FieldComplex>
<my:Root>

Declaring FieldComplex as object will insert these attributes on the <my:FieldComplex> element:

 xmlns:q1="http://www.w3.org/2001/XMLSchema" p3:type="q1:string" xmlns:p3="http://www.w3.org/2001/XMLSchema-instance

and I don't want that. I also don't want to use different classes for serialization and deserialization.

So, is it possible?

To make a long story short, is it possible to have this class:

public class MyRoot
{
    public string FieldBasic { get; set; }
    public string FielComplex { get; set; }
}

Serialize to this:

<my:Root xmlns:my="http://foo/bar">
    <my:FieldBasic>content</my:FieldBasic>
    <my:FieldComplex>content</my:FieldComplex>
<my:Root>

and deserialize from this:

<my:Root xmlns:my="http://foo/bar">
    <my:FieldBasic>content</my:FieldBasic>
    <my:FieldComplex>
        <html xml:space="preserve" xmlns="http://www.w3.org/1999/xhtml">
            <div><h1>content</h1></div>
        </html>
    </my:FieldComplex>
<my:Root>

?

P.S. Just to explain "the why?". I have a class witch gets serialized. The serialized XML then travels through multiple nodes in the application and eventually comes back but altered like above. The layers do some XML validation and having extra attributes or elements on input fail the validation and stops the flow. I want to map the return XML to the same class. The content is just strings from it's point of view but of course not the same for serialization/deserialization :(


回答1:


This isn't quite finished because I can't remember if you can / how to add the namespace prefix to the root element in Xml Serialization. But if you implement the IXmlSerializable interface in your MyRoot class like this:

[XmlRoot("Root", Namespace="http://foo/bar")]
public class MyRoot : IXmlSerializable

Then write the XML serialization methods yourself, something like this:

        void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
        {
            reader.MoveToContent();
            var outerXml = reader.ReadOuterXml();
            XElement root = XElement.Parse(outerXml);

            this.FieldBasic = root.Elements(XName.Get("FieldBasic", "http://foo/bar")).First().Value;
            this.FieldComplex = root.Elements(XName.Get("FieldComplex", "http://foo/bar")).First().Elements().First().Value.Trim();
        }



        void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
        {
            writer.WriteRaw(String.Format("\r\n\t<my:FieldBasic>\r\n\t\t{0}\r\n\t</my:FieldBasic>", this.FieldBasic));
            writer.WriteRaw(String.Format("\r\n\t<my:FieldComplex>\r\n\t\t{0}\r\n\t</my:FieldComplex>\r\n", this.FieldComplex));
        }

(Return null from the GetSchema method)

This should get you at least pretty close to what you're after.

You may also find these links helpful.

IXmlSerializable

Namespaces




回答2:


You could use CDATA in the XML to indicate that the contents is a string literal:

<my:Root xmlns:my="http://foo/bar">
  <my:FieldBasic>content</my:FieldBasic>
  <my:FieldComplex>
    <![CDATA[
      <html xml:space="preserve" xmlns="http://www.w3.org/1999/xhtml">
        <div><h1>content</h1></div>
      </html>
    ]]>
  </my:FieldComplex>
</my:Root>


来源:https://stackoverflow.com/questions/8730764/deserialize-element-value-as-string-although-it-contains-mixed-content

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!