使用XMLSerializer在vb.net中创建类oXML的序列化的XML字符串时,如下所示:
Dim x As New Xml.Serialization.XmlSerializer(oXML.GetType, "urn:oecd:blah:blah")
Dim xmlns = New XmlSerializerNamespaces()
xmlns.Add(String.Empty, "urn:oecd:blah:blah")
xmlns.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance")
xmlns.Add("sfa", "urn:oecd:blah:blah1")
xmlns.Add("iso", "urn:oecd:blah:blah2")
xmlns.Add("ftc", "urn:oecd:blah:blah")
Dim sw As New IO.StringWriter()
x.Serialize(sw, oXML, xmlns)
你会注意到我重复添加名称空间“urn:oecd:blah:blah”作为xmlns对象上的空“默认”命名空间以及x As New Xml.Serialization.XmlSerializer的定义。
问题是这个特定的命名空间只能使用前缀ftc进行渲染,并且不会显示默认值。如果我注释掉ftc命名空间的添加,并再次运行它,则会正确呈现默认命名空间。有没有办法告诉序列化器这个命名空间是默认使用还是前缀为ftc?我假设它是因为命名空间被使用了两次,既是默认的,也是一个忽略它的前缀?
答案 0 :(得分:1)
XmlSerializer
在传递XmlSerializerNamespaces
两个前缀为相同名称空间的情况下没有定义的行为。它可以选择任一前缀,结果在语义上是相同的。此外,从类的reference source开始,名称空间存储在哈希表中,因此它们的顺序是不可预测的。但由于XML在任何一种方式都具有相同的含义,因此最简单的方法就是不要担心它。
如果出于某种原因,必须在XML中具有重复的命名空间,并且必须使用默认前缀优先于该命名空间中元素的等效命名前缀,可以序列化为XDocument
,然后手动添加缺少的重复项:
Public Module XObjectExtensions
<System.Runtime.CompilerServices.Extension>
Public Function SerializeToXDocument(Of T)(obj As T, serializer As XmlSerializer, ns As XmlSerializerNamespaces) As XDocument
Dim doc = New XDocument()
Using writer = doc.CreateWriter()
serializer = If(serializer, New XmlSerializer(obj.GetType()))
serializer.Serialize(writer, obj, ns)
End Using
If doc.Root IsNot Nothing AndAlso ns IsNot Nothing Then
' Add missing namespaces
For Each name In ns.ToArray().Except(doc.Root.Attributes().Where(Function(a) a.IsNamespaceDeclaration).Select((Function(a) New XmlQualifiedName(a.Name.LocalName, a.Value))))
doc.Root.Add(New XAttribute("xmlns" + (If(String.IsNullOrEmpty(name.Name), String.Empty, ":" + name.Name)), name.Namespace))
Next
End If
Return doc
End Function
End Module
然后使用它:
Dim xDoc = oXML.SerializeToXDocument(x, xmlns)
Dim xml2 as String
Using sw = New IO.StringWriter()
xDoc.Save(sw)
xml2 = sw.ToString()
End Using
示例dotnetfiddle。
现在,在您的情况下,省略了默认命名空间,以支持重复的前缀命名空间。如果由于某种原因,XmlSerializer
选择执行相反的操作(并且没有记录它将选择它),那么在根文档的命名空间列表的末尾添加缺少的命名空间将导致要使用命名前缀写入的所有元素。这是因为事实证明,当写XElement
,name/namespace pairs are pushed onto a stack during serialization时,使用了lattermost。要解决此问题,您可以调整XDocument Save Removing Node Prefixes中的代码并将默认前缀移至属性列表的 end ,而不是开头。