开发者

Remove xsi:type from generated xml when serializing

开发者 https://www.devze.com 2023-04-11 07:51 出处:网络
I am sending XML externally. One of the node called \"datafield\" has an element called \"value\". This may contain normal text content, or an html content (which I need to wrap in CData).

I am sending XML externally.

One of the node called "datafield" has an element called "value". This may contain normal text content, or an html content (which I need to wrap in CData).

So, I created a base class (ProvisionD开发者_如何学CataField) with 2 classes inherits from it (ProvisionTextField, and ProvisionCDataField) as follows:

<XmlInclude(GetType(ProvisionTextField))>
<XmlInclude(GetType(ProvisionCDataField))>
Public MustInherit Class ProvisionDataField

    <XmlAttribute("datatype")>
    Public Property DataType As String

    <XmlElement("name")>
    Public Property Name As String

End Class

Public Class ProvisionCDataField
    Inherits ProvisionDataField

    <XmlIgnore()>
    Public Property ValueContent As String

    <XmlElement("value")>
    Public Property Value() As XmlCDataSection
        Get
            Dim doc As New XmlDocument
            Return doc.CreateCDataSection(ValueContent)
        End Get
        Set(ByVal value As XmlCDataSection)
            ValueContent = value.Value
        End Set
    End Property
End Class

Public Class ProvisionTextField
    Inherits ProvisionDataField

    <XmlElement("value")>
    Public Property Value As String

End Class

When I serialize,I get something like this:

   <entitydata entitytype="company">
      <datafield xsi:type="ProvisionTextField" datatype="string">
        <name>companyAcronym</name>
        <value>testCompany</value>
      </datafield>
      <datafield xsi:type="ProvisionCDataField" datatype="string">
        <name>ssocontent</name>
        <value><![CDATA[<html><body> HTML Content</body></html>]]></value>
      </datafield>
    </entitydata>

All good except that I've been told that I have to remove the "xsi:type" from the xml. So instead, I need my generated xml to look like this:

   <entitydata entitytype="company">
      <datafield datatype="string">
        <name>companyAcronym</name>
        <value>testCompany</value>
      </datafield>
      <datafield datatype="string">
        <name>ssocontent</name>
        <value><![CDATA[<html><body> HTML Content</body></html>]]></value>
      </datafield>
    </entitydata>

Is that possible?


This is the answer I am looking for - it will ensure that the xsi:type resulted from XmlInclude attribute used in inheritance is omitted:

    ElseIf ns = XmlSchema.InstanceNamespace Then
        ' Omits all XSI attributes
        _skip = True
        Return
    End If

While this section will omit the xmlns:xsd and xmlns:xsi from the root

    If prefix = "xmlns" AndAlso (localName = "xsd" OrElse localName = "xsi") Then
        ' Omits XSD and XSI from root
        _skip = True
        Return

Full codes:

Imports System.IO
Imports System.Xml
Imports System.Xml.Schema

Public Class PlainXmlTextWriter
    Inherits XmlTextWriter

    Public Sub New(ByVal w As TextWriter)
        MyBase.new(w)
    End Sub

    Public Sub New(ByVal w As Stream, ByVal encoding As Encoding)
        MyBase.new(w, encoding)
    End Sub

    Public Sub New(ByVal filename As String, ByVal encoding As Encoding)
        MyBase.new(filename, encoding)
    End Sub

    Dim _skip As Boolean = False

    Public Overrides Sub WriteStartAttribute(ByVal prefix As String, ByVal localName As String, ByVal ns As String)
        If prefix = "xmlns" AndAlso (localName = "xsd" OrElse localName = "xsi") Then
            ' Omits XSD and XSI from root
            _skip = True
            Return
        ElseIf ns = XmlSchema.InstanceNamespace Then
            ' Omits all XSI attributes
            _skip = True
            Return
        End If
        MyBase.WriteStartAttribute(prefix, localName, ns)
    End Sub

    Public Overrides Sub WriteString(ByVal text As String)
        If _skip Then Return
        MyBase.WriteString(text)
    End Sub

    Public Overrides Sub WriteEndAttribute()
        If _skip Then
            _skip = False
            Return
        End If
        MyBase.WriteEndAttribute()
    End Sub
End Class


You will have to overwrite xmlwriter.

This blogpost (not mine) shows you how.

Here is the VB.Net version.

Imports System.Xml.Serialization
Imports System.Xml
Imports System.IO
Imports System.Text

Module Module1

    Sub Main()
        Dim p As New ProvisionCDataField()
        p.Name = "test"
        Dim sw1 = New StringWriter()
        Dim xs1 As New XmlSerializer(GetType(ProvisionDataField))
        xs1.Serialize(New XmlTextWriter(sw1), p)
        Console.WriteLine(sw1.ToString())
        Dim sw2 = New StringWriter()
        Dim xs2 As New XmlSerializer(GetType(ProvisionDataField))
        xs2.Serialize(New NonXsiTextWriter(sw2), p)
        Console.WriteLine(sw2.ToString())
        Console.ReadLine()
    End Sub

End Module

Public Class NonXsiTextWriter
    Inherits XmlTextWriter

    Public Sub New(ByVal w As TextWriter)
        MyBase.new(w)
    End Sub

    Public Sub New(ByVal w As Stream, ByVal encoding As Encoding)
        MyBase.new(w, encoding)
    End Sub

    Public Sub New(ByVal filename As String, ByVal encoding As Encoding)
        MyBase.new(filename, encoding)
    End Sub

    Dim _skip As Boolean = False

    Public Overrides Sub WriteStartAttribute(ByVal prefix As String, ByVal localName As String, ByVal ns As String)
        If localName = "xsi" Then
            _skip = True
            Return
        End If
        MyBase.WriteStartAttribute(prefix, localName, ns)
    End Sub

    Public Overrides Sub WriteString(ByVal text As String)
        If _skip Then Return
        MyBase.WriteString(text)
    End Sub

    Public Overrides Sub WriteEndAttribute()
        If _skip Then
            _skip = False
            Return
        End If
        MyBase.WriteEndAttribute()
    End Sub
End Class

<XmlInclude(GetType(ProvisionTextField))>
<XmlInclude(GetType(ProvisionCDataField))>
Public MustInherit Class ProvisionDataField

    <XmlAttribute("datatype")>
    Public Property DataType As String

    <XmlElement("name")>
    Public Property Name As String

End Class

Public Class ProvisionCDataField
    Inherits ProvisionDataField

    <XmlIgnore()>
    Public Property ValueContent As String

    <XmlElement("value")>
    Public Property Value() As XmlCDataSection
        Get
            Dim doc As New XmlDocument
            Return doc.CreateCDataSection(ValueContent)
        End Get
        Set(ByVal value As XmlCDataSection)
            ValueContent = value.Value
        End Set
    End Property
End Class

Public Class ProvisionTextField
    Inherits ProvisionDataField

    <XmlElement("value")>
    Public Property Value As String

End Class

With this as the result.

<?xml version="1.0" encoding="utf-16"?>
 <ProvisionDataField xmlns:xsi="http://www .w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="ProvisionCDataField">
   <name>test</name><value><![CDATA[]]></value>
 </ProvisionDataField> 

<?xml version="1.0" encoding="utf-16"?>
 <ProvisionDataField xmlns:xsd="http://www.w3.org/2001/XMLSchema" d1p1:type="ProvisionCDataField"  xmlns:d1p1="http://www.w3.org/2001/XMLSchema-instance">
  <name>test</name><value><![CDATA[]]></value>
 </ProvisionDataField>


No need to override XmlWriter, just use an instance of XmlSerializerNamespace:

Sub Main()
    Dim xSer As New XmlSerializer(GetType(MyType))

    Dim sb As New StringBuilder()

    Dim obj As MyType = getAnInstanceOfMyType()

    Using wrt As New StringWriter(sb)
        Dim ns As New XmlSerializerNamespaces
        ns.Add("", "")

        xSer.Serialize(wrt, obj, ns)

    End Using

    Console.WriteLine(sb.ToString())

    Console.ReadLine()
End Sub

This will result in the xml having no namespaces at all.

EDIT: Changed to VB code

EDIT 2: Upon further testing, the test code I used only removed the namespace declarations from the resulting xml. My original test did not produce the xsi:type attributes on the elements even though I used the classes provided by the OP, so I cannot determine if the code that I posted will remove them, as John Saunder alluded to in the comments. I presumed that if the namespaces were removed, then the xsi:type attributes would also be removed, but the code I posted does not prove this.

0

精彩评论

暂无评论...
验证码 换一张
取 消