Удалить xsi: type из сгенерированного xml при сериализации - PullRequest
0 голосов
/ 05 октября 2011

Я отправляю XML извне.

Один из узлов с именем «поле данных» имеет элемент с именем «значение».Это может содержать обычный текстовый контент или 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>

Все хорошо, кроме того, что мне сказали, что я должен удалить "xsi: type" из xml.Поэтому вместо этого мне нужно, чтобы мой сгенерированный 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 ]

2 голосов
/ 06 октября 2011

Это ответ, который я ищу - он гарантирует, что xsi: type, полученный из атрибута XmlInclude, используемого в наследовании, опущен:

    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 голос
/ 05 октября 2011

Вам придется перезаписать xmlwriter.

Этот пост (не мой) показывает вам, как.

Вот версия 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>
0 голосов
/ 05 октября 2011

Нет необходимости переопределять 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, поэтому я не могу определить, удалит ли их код, который я разместил, как упоминал Джон Саундер в комментариях. Я предполагал, что если пространства имен будут удалены, то атрибуты xsi: type также будут удалены, но размещенный мною код не доказывает этого.

...