android泛型xml序列化,Xml序列化当泛型不同时序列化(反序列化)为不同的Xml节点名称...

本文探讨了在对接第三方接口时遇到的XML数据契约定义问题,特别是业务数据XML节点名称不一致的情况。文章通过示例展示了如何通过抽象类和泛型结合的方式解决这一问题,并提供了自定义XML序列化类的实现,以适应不同业务需求。同时,文中提到了代码维护性和可扩展性的考虑,以及如何通过LinqToXml进一步定制序列化和反序列化过程。
摘要由CSDN通过智能技术生成

在我们提供接口服务给第三方调用时,一般会采用Request/Response模式,即请求与响应都采用统一的外部封装,真正的业务数据则由Request/Resonse的某个参数比如Data之类的类进行承担,以Request为例,该请求类假设定义成如下内容:

///

/// 数据请求类

///

///

[XmlRoot("Request")]

public class Request

{

///

/// 请求外部唯一性流水号,用于Resposne对应

///

public string RequestId { get; set; }

///

/// 请求日期 yyyy-MM-dd HH:mm:ss格式

///

public string RequestDate { get; set; }

///

/// 请求业务数据

///

public T Data { get; set; }

}这里初始化该类的一个具体定义

Request request = new Request

{

Data = 1,

RequestDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),

RequestId = Guid.NewGuid().ToString()

}其Xml序列化结果默认如下

6a9a99fc-7731-41d9-87b1-2cc637b0afdc

2018-03-07 14:38:08

1

这里业务数据部分不管泛型类为什么,该业务的

Xml节点名称均为Data,这是很正常的一种数据契约定义方式,但实际我们接入第三方接口时,很可能会碰到另外一种情况,甚至可以说是反人类的定义方式,同一个第三方接口服务,

接口A和接口B的业务数据Xml节点名称不一样!!!具体可能如下

6a9a99fc-7731-41d9-87b1-2cc637b0afdc

2018-03-07 14:38:08

1

这种情况下,前面的Request肯定是无法支持的,所以需要对Request进行调整

///

/// 数据请求类

///

///

[XmlRoot("Request")]

public abstract class Request

{

///

/// 请求外部唯一性流水号,用于Resposne对应

///

public string RequestId { get; set; }

///

/// 请求日期 yyyy-MM-dd HH:mm:ss格式

///

public string RequestDate { get; set; }

///

/// 请求业务数据

///

[XmlIgnore]

public abstract T Data { get; set; }

}注意除了

Data属性被定义成了abstract外,该节点还设置了XmlIgnore特性,如果不设置该特性,那么子类自定义XmlElement后再进行Xml序列化会产生异常,下面是业务A的定义

[XmlRoot("Request")]

public class RequestForA : Request

{

[XmlElement("BusinessA")]

public override int Data { get; set; }

}注意该类也

必须要定义XmlRoot特性,否则序列化出来的Xml最外层节点名称将为RequestForA,同理对于业务B也需要如此操作设置(再说一次这么提供接口服务的第三方真是反人类!!!)

最后实际进行业务定义的地方进行调整

var request = new RequestForA

{

Data = 1,

RequestDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),

RequestId = Guid.NewGuid().ToString()

};这样就可以对不同的业务,序列化不同的Xml节点名称(当然反序列化也是没有任何问题的),顺带补充下Xml序列化辅助类

using System.IO;

using System.Text;

using System.Text.RegularExpressions;

using System.Xml;

using System.Xml.Serialization;

///

/// xml序列化辅助类

///

public static class XmlHelper

{

///

/// xml序列化

///

/// 泛型

/// 待序列化对象

/// 字符编码,不指定则utf-8

/// 是否显示xml声明

/// 是否移除默认的xmlns:xsi命名空间(注:如果待序列化对象指定了NameSpace还是会序列化出对应的命名空间)

///

public static string Serializer(this T obj, Encoding encoding = null, bool showDeclaration = true, bool removeDefaultNameSpace = false)

{

XmlSerializer serializer = new XmlSerializer(typeof(T));

if (encoding == null)

{

encoding = Encoding.UTF8;

}

using (MemoryStream stream = new MemoryStream())

{

XmlWriterSettings xws = new XmlWriterSettings();

xws.Indent = true;

xws.OmitXmlDeclaration = !showDeclaration;

xws.Encoding = encoding;

using (XmlWriter xtw = XmlWriter.Create(stream, xws))

{

XmlSerializerNamespaces ns = new XmlSerializerNamespaces();

if (removeDefaultNameSpace)

{

ns.Add("", "");

}

serializer.Serialize(xtw, obj, ns);

stream.Position = 0;

string xml = encoding.GetString(stream.GetBuffer());

//这种方法生成的xml字符串在不同Encoding下不知道为啥可能会有不可见字符

if (xml[0] != '

{

var sIdx = xml.IndexOf('

var eIdx = xml.LastIndexOf('>');

xml = xml.Substring(sIdx, eIdx - sIdx + 1);

//return Regex.Replace(xml, @"^[\s\S]*?(?=]*?$", string.Empty);//正则存在性能问题

}

return xml;

}

}

}

///

/// xml反序列化

///

/// 泛型

/// xml内容

///

public static T Deserialize(this string xml)

{

using (StringReader sr = new StringReader(xml))

{

XmlSerializer serializer = new XmlSerializer(typeof(T));

try

{

return (T)serializer.Deserialize(sr);

}

catch(Exception e)

{

return default(T);

}

}

}

}好吧,上面写了那么多,实际这么做每种业务服务都要定义一个class定义,一旦业务多了,对于强迫症或者代码洁癖者可能是一种折磨,毕竟每种业务除了自身的业务类定义外,还需要定义外部包含类,那是否还有其他可行的方法呢?

答案是肯定的,但这种答案是彻底定制的!!!定制的思路是这样的,既然你的业务节点名称不同,那在序列化或反序列化时,针对这特定的业务名称进行特殊处理不就行了?下面是以LinqToXml进行Xml解析的示例代码:

///

/// 完全定制的xml序列化类,只可做参考,不能直接拿来用

///

public class XmlHelperCustomized

{

///

/// 序列化

///

///

///

/// 要替换的业务节点名称

///

public static string Serializer(Request request, string nodeName)

{

var xml = XmlHelper.Serializer(request);

var root = XElement.Parse(xml);

var ele = root.Element("Data");

if (ele != null)

{

ele.Name = nodeName;

}

return root.ToString();

}

///

/// 反序列化

///

///

///

/// 业务节点名称

/// 业务数据是否需要xml反序列化,true表示是

///

public static Request Deserialize(string xml, string nodeName, bool dataIsXml)

{

var request = XmlHelper.Deserialize>(xml);

var root = XElement.Parse(xml);

var ele = root.Element(nodeName);

if (ele != null)

{

T obj;

if (dataIsXml)

{

obj = XmlHelper.Deserialize(ele.ToString());

}

else

{

obj = (T)Convert.ChangeType(ele.Value, typeof(T));

}

request.Data = obj;

}

return request;

}

}这里为该类业务定制了一个特定的Xml序列化类(注意该部分代码依赖上面的XmlHelper),相应的使用例子代码如下:

var request = new Request//注意这里的Request是非abstract的那个

{

Data = 1,

RequestDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),

RequestId = Guid.NewGuid().ToString()

};

var xml = XmlHelperCustomized.Serializer(request, "BusinessA");

var requestA = XmlHelperCustomized.Deserialize(xml, "BusinessA", false);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值