前言:xml的操作方式有多种,但要论使用频繁程度,博主用得最多的还是linq to xml的方式,觉得它使用起来很方便,就用那么几个方法就能完成简单xml的读写。之前做的一个项目有一个很变态的需求:c#项目调用不知道是什么语言写的一个webservice,然后添加服务引用总是失败,通过代理的方式动态调用也总是报错,最后没办法,通过发送原始的webrequest请求直接得到对方返回的一个xml文件。注意过webservice的wsdl文件的朋友应该知道这个是系统生成的xml文件,有点复杂,研究了半天终于能正常读写了。今天在这里和大家分享下。
1、介绍之前,首先回顾下linq to xml的方式读写简单xml的方法
(1)读取xml
?xml version="1.0" encoding="utf-8"?>
<bizadslist>
<addata aid="1" image="baidu.jpg" link="www.baidu.com" title="百度"/>
<addata aid="2" image="qq.jpg" link="www.qq.com" title="腾讯"/>
</bizadslist>
var strpath = path.combine(appdomain.currentdomain.basedirectory, @"data\test.xml");
xdocument adlist = xdocument.load(strpath);
var ad = from a in adlist.descendants("bizadslist").elements("addata")
select new
{
image = a.attribute("image").value,
link = a.attribute("link").value,
title = a.attribute("title").value
};
string s = "";
foreach (var a in ad)
s += a.image;
(2)写xml
/// <summary>
/// 根据得到的document集合生成xml
/// </summary>
/// <param name="lstdocumentbd"></param>
/// <param name="docne"></param>
/// <param name="strspidertime"></param>
/// <param name="strnewrate"></param>
private static void savexmlbylstdocument(list<document> lstdocumentbd, document docne, string strspidertime, string strnewrate)
{
try
{
xdocument xdoc = new xdocument();
xelement xroot = new xelement(cspiderconst.xml_ele_root);
//1.构造device节点
xelement xdevice = new xelement(cspiderconst.xml_ele_device);
//2.构造ne节点
xelement xne = new xelement(cspiderconst.xml_ele_ne);
foreach (var odocne in docne)
{
xelement xitem = new xelement(cspiderconst.xml_ele_item, new xattribute(cspiderconst.xml_prop_name, odocne.key), odocne.value);
xne.add(xitem);
}
//这里增加一个<item name='newrate'>和<item name='spidertimeex'>节点用来保存当前这次的利用率和当次的采集时间
addnewrateandspidertime(strspidertime, strnewrate, xne);
xdevice.add(xne);
//3.循环构造bd节点并添加到device节点中
foreach (var odocument in lstdocumentbd)
{
xelement xbd = new xelement(cspiderconst.xml_ele_bd);
foreach (var odocbd in odocument)
{
xelement xitem = new xelement(cspiderconst.xml_ele_item, new xattribute(cspiderconst.xml_prop_name, odocbd.key), odocbd.value);
xbd.add(xitem);
}
addnewrateandspidertime(strspidertime, strnewrate, xbd);
xdevice.add(xbd);
}
xroot.add(xdevice);
xdoc.add(xroot);
//4.保存到采集器本地,以服务器的时间和网元的assetid来命名
var strdirectorypath = path.combine(appdomain.currentdomain.basedirectory, "reportfailed\\");
if (!directory.exists(strdirectorypath))
{
directory.createdirectory(strdirectorypath);
}
xdoc.save(strdirectorypath + docne[tbldevicelcbb.prop_assetid] + "_" + strspidertime.replace(":", "_") + ".xml");
}
catch
{
clogservice.instance.debug("保存xml失败");
}
}
通过xdocument、xelement对象和element()、elements()两个方法能完成大部分xml文件的操作。
2、进入今天的正题:读写带命名空间的xml文件。
首先来看一段xml
<?xml version="1.0" encoding="utf-8" ?>
<dataset xmlns="http://webxml.com.cn/">
<xs:schema xmlns="" xmlns:xs="http://www.w3.org/2001/xmlschema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="getregion">
<msdata:aa>
test
</msdata:aa>
<xs:element name="getregion" msdata:isdataset="true" msdata:usecurrentlocale="true">
<xs:element name="province">
<xs:sequence>
<xs:element name="regionid" type="xs:string" minoccurs="0"/>
<xs:element name="regionname" type="xs:string" minoccurs="0"/>
</xs:sequence>
</xs:element>
</xs:element>
</xs:schema>
</dataset>
第一次看到这个文件确实让人萌神了,比如需要取一个msdata:isdataset=”true”这个属性,该怎么取…
解析之前,先来分析下这段xml,<dataset xmlns=”http://webxml.com.cn/”>这段里面有一个xmlns属性,这个属性是每一个标签自带的属性,不信你可以新建一个xml文件,然后在任何一个标签里面输入xmlns属性,后面都会出来很多的系统自带的命名空间。这个属性表示所属标签在哪个命名空间下面,所以在取的时候要带上这个命名空间。
先来看看解析的代码:
var strpath = path.combine(appdomain.currentdomain.basedirectory, @"data\test.xml");
var oroot = xdocument.load(strpath);
//取dataset标签
var odataset = oroot.element(xname.get("dataset", "http://webxml.com.cn/"));
//取schema标签
var oschema = odataset.element(xname.get("schema", "http://www.w3.org/2001/xmlschema"));
//取element标签
var oelement = oschema.element(xname.get("element", "http://www.w3.org/2001/xmlschema"));//这两个节点都是以xs打头,所以命名空间都是xs的命名空间
//取element标签下面的isdataset属性
var oelementvalue = oelement.attribute(xname.get("isdataset", "urn:schemas-microsoft-com:xml-msdata"));
//取aa标签
var oaa = oschema.element(xname.get("aa", "urn:schemas-microsoft-com:xml-msdata"));
我们来解析下几个关键的地方:
(1)我们来解析下
<xs:schema xmlns="" xmlns:xs="http://www.w3.org/2001/xmlschema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="getregion">
这一句,最前面的”xs”表示标签所属命名空间的变量,xmlns:xs=”http://www.w3.org/2001/xmlschema”这个表示xs这个命名空间的值。所以要得到schema这个标签需要带上命名空间var oschema = odataset.element(xname.get(“schema”, “http://www.w3.org/2001/xmlschema”));这个标签还定义了另一个命名空间xmlns:msdata=”urn:schemas-microsoft-com:xml-msdata”。
(2)再来看看aa标签
<msdata:aa>
test
</msdata:aa>
msdata就是上面schema标签里面定义的另一个命名空间,表示aa标签属于msdata命名空间下面。
(3)再看来看属性的取法:
<xs:element name="getregion" msdata:isdataset="true" msdata:usecurrentlocale="true">
如果要取msdata:isdataset=”true”,由于这个属性也带有命名空间,所以取属性时也要加上命名空间了。所以需要这样取。
var oelementvalue = oelement.attribute(xname.get(“isdataset”, “urn:schemas-microsoft-com:xml-msdata”));
现在大伙们应该对这种xml有一个更加清晰的认识了吧。其实一般情况下这种场景比较少见,因为这么复杂的xml一般是由引用服务时代理对象去解析的。但如果真的有这么变态的需求我们也不用担心了。在此记录下,以后如果大家遇到希望能节约大伙的时间。
以上就是c#基础系列:linq to xml读写xml的内容。
