【问题标题】:XML Serialisation between two types (common and web service type)两种类型(普通和 Web 服务类型)之间的 XML 序列化
【发布时间】:2013-12-17 12:45:27
【问题描述】:

如何从一个公共对象转换为 Web 服务对象(相同的对象但不同的命名空间 - Web 服务代理更改命名空间),以及如何使用 Xml 序列化从 Web 服务转换为公共对象。

下面的代码没有例外,但是反序列化的对象属性设置为它们的默认值,而不是它们应该具有的值。正如@Mark Gravel 在下面的答案中指出的那样,这是因为当您序列化到 Web 服务对象时,它会添加额外的 Xml 命名空间。 我尝试了多种方法,例如使用 Xml.Serialization.XmlSerializerNamespaces 并在序列化时设置默认命名空间,但我要么得到相同的结果,要么做错了事,并在反序列化时出现 Xml 错误。

我意识到这比直接映射对象属性要慢(性能),但它非常大,我想让原型快速运行而不必每次都转换对象。有没有办法在反序列化之前完全删除命名空间并在序列化时添加命名空间? - 添加和删除xmlns="http://[host.co.uk]/ 位的结构化方式。

请注意,Web 服务归第三方所有(因此无法更改该代码),并且该对象没有特殊的 Xml 修饰。涉及多个 Web 服务,因此命名空间将在运行时根据服务 URL 发生变化。

要序列化,我使用以下代码:

Dim serializer As New Xml.Serialization.XmlSerializer(requestParams.GetType)
Using strWriter As New IO.StringWriter()
    serializer.Serialize(strWriter, requestParams)
    Return strWriter.ToString
End Using

要反序列化,我使用以下代码:

Dim serializer As New XmlSerializer(GetType(T))
Using strReader As New IO.StringReader(serializedXml)
    Return DirectCast(serializer.Deserialize(strReader), T)
End Using

供参考,序列化的普通对象:

<?xml version="1.0" encoding="utf-16"?>
<SearchPartsRequest>
  <LocationCode>01</LocationCode>
  <PartCriteria>
    <PartNo>1064762</PartNo>
  </PartCriteria>
  <WildCardSearch>false</WildCardSearch>
</SearchPartsRequest>

序列化的网络服务对象:

<?xml version="1.0" encoding="utf-16"?>
<SearchPartsRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <LocationCode xmlns="http://host.co.uk/">01</LocationCode>
  <PartCriteria xmlns="http://host.co.uk/">
    <PartNo>1064762</PartNo>
  </PartCriteria>
</SearchPartsRequest>

【问题讨论】:

    标签: .net web-services xml-serialization .net-2.0


    【解决方案1】:

    您可能需要考虑为使用的命名空间自定义 Serialize 和 Deserialize 函数。如此处所述: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlattributes.xmlns(v=vs.110).aspx

    【讨论】:

    • 看起来不错,你能在上面的上下文中提供一个例子吗?我还没有时间尝试,50分需要奖励。
    【解决方案2】:

    Xml 命名空间。你的不匹配。您需要正确声明命名空间,例如:

    [XmlElement(Namespace="http://host.co.uk/")]
    public string LocationCode {get;set;}
    

    【讨论】:

    • 谢谢 Marc,是的,我认为是这样,不幸的是,我无法按照您建议的方式解决此问题(不仅有一个主机)。我需要在序列化或反序列化期间控制它。
    【解决方案3】:

    去除命名空间的最简单方法就是使用正则表达式。因此(在 C# 中对不起):

    var newXml = System.Text.RegularExpressions.Regex.Replace(xml, @"(xmlns:?[^=]=[""][^""][""]) ", "", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Multiline);

    【讨论】:

    • 理想情况下我想用托管类来做,在这种情况下我可以使用 string.replace。
    【解决方案4】:

    System.Xml.Serialization.XmlAttributes.Xmlns = False 是关键。

    这是一个例子:

    Dim atts As New System.Xml.Serialization.XmlAttributes()
    ' Set to true to preserve namespaces, or false to ignore them.
    atts.Xmlns = False
    
    Dim xover As New System.Xml.Serialization.XmlAttributeOverrides()
    ' Add the XmlAttributes and specify the name of  
    ' the element containing namespaces.
    xover.Add(secCred.GetType, String.Empty, atts)
    
    Dim serializer As New System.Xml.Serialization.XmlSerializer(secCred.GetType, xover)
    Using strWriter As New IO.StringWriter()
        serializer.Serialize(strWriter, secCred)
        xml = strWriter.ToString
    End Using
    

    字符串xml 将包含(注意xmlns="http://host.co.uk/" 已被删除)并可反序列化为通用对象类型:

    <SearchPartsRequest>
      <LocationCode>01</LocationCode>
      <PartCriteria>
        <PartNo>1064762</PartNo>
      </PartCriteria>
      <WildCardSearch>false</WildCardSearch>
    </SearchPartsRequest>
    

    反序列化似乎无关紧要,您可以像往常一样执行此操作,因为命名空间会自动为您重新添加(如果您再次序列化的位置)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-21
      • 1970-01-01
      • 2020-04-13
      • 1970-01-01
      相关资源
      最近更新 更多