序列化时从生成的xml中删除xsi:type

时间:2011-10-05 03:57:52

标签: .net xml vb.net xml-serialization cdata

我在外部发送XML。

一个名为“datafield”的节点有一个名为“value”的元素。这可能包含普通文本内容或html内容(我需要将其包装在CData中)。

因此,我创建了一个基类(ProvisionDataField),其中有2个类继承自它(ProvisionTextField和ProvisionCDataField),如下所示:

<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

当我序列化时,我会得到类似的结果:

   <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>

一切都很好,除了我被告知我必须从xml中删除“xsi:type”。所以相反,我需要生成的xml看起来像这样:

   <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>

这可能吗?

3 个答案:

答案 0 :(得分:2)

这是我正在寻找的答案 - 它将确保省略继承中使用的XmlInclude属性产生的xsi:类型:

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

虽然本节将从根

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

完整代码:

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

答案 1 :(得分:1)

您必须覆盖xmlwriter。

This blogpost(不是我的)告诉你如何。

这是VB.Net版本。

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

结果就是这样。

<?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>

答案 2 :(得分:-1)

无需重写XmlWriter,只需使用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

这将导致xml根本没有名称空间。

编辑:更改为VB代码

编辑2:经过进一步测试,我使用的测试代码仅从生成的xml中删除了命名空间声明。我的原始测试没有在元素上产生xsi:type属性,即使我使用了OP提供的类​​,因此我无法确定我发布的代码是否会删除它们,正如John Saunder在评论中提到的那样。我假设如果删除了名称空间,那么xsi:type属性也会被删除,但是我发布的代码并没有证明这一点。