Linq to Xml读取复杂xml(带命名空间)
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一般是由引用服务时代理对象去解析的。但如果真的有这么变态的需求我们也不用担心了。在此记录下,以后如果大家遇到希望能节约大伙的时间。
Linq to js使用小结
1、什么是Linq to js :C# 3.0推出了.Net独有的新特性:Linq。自从有了Linq,程序员再也不用担心对集合的操作了。同理,Linq to js 当然也就是对前端集合变量进行操作的一种技术框架。
2、怎么使用:因为是前端框架,所以你懂得,只需要引用一个js文件即可。这里还是附上官网地址:http://jslinq.codeplex.com/.这上面有文件和Demo,可以上去看看。使用方式主要有两种:使用方法一、直接引用js文件;使用方法二、使用Nuget Package 安装Linq to js。在PM安装控制台中输入Install-Package jslinq。
本篇以Linq to js的lamada表达式写法的方式来以此介绍常用方法。我们从官网上面下载下载的文件如下图
我们只需要引用linq.js文件即可。
(1)条件查询:Where
var myList = [ { Name: "Jim", Age: 20 }, { Name: "Kate", Age: 21 }, { Name: "Lilei", Age: 18 }, { Name: "John", Age: 14 }, { Name: "LinTao", Age: 25 } ]; var arrRes = Enumerable.From(myList).Where("x=>x.Name=='Jim'").ToArray();
arrRes的结果为 [{"Name":"Jim","Age":20}]
我们来看看这种写Lamada表达式的原型:
var arrRes = Enumerable.From(myList).Where(function (i) { return i.Name=='Jim'; });
参数i是对应的集合里面的实体模型,返回类型为bool类型。有没有和C#里面的扩展函数Where的定义很像:public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);参数Func<TSource, bool> predicate为匿名委托,需要传入实体模型TSource,然后返回值为bool类型。其实感觉linq to js的使用就是参照c#里面的定义来的。
(2)条件选择:Select
var myList = [ { Name: "Jim", Age: 20 }, { Name: "Kate", Age: 21 }, { Name: "Lilei", Age: 18 }, { Name: "John", Age: 14 }, { Name: "LinTao", Age: 25 } ]; var arrRes = Enumerable.From(myList).Select("x=>x.Age*10").ToArray();
arrRes得到结果 [200,210,180,140,250]
(3)排序、去重:OrderBy、Distinct
var myList = [ { Name: "Jim", Age: 20 }, { Name: "Kate", Age: 21 }, { Name: "Lilei", Age: 18 }, { Name: "John", Age: 14 }, { Name: "LinTao", Age: 25 } ]; var arrRes = Enumerable.From(myList).OrderBy("x=>x.Age").ToArray();//降序OrderByDescending()
得到的结果会按照Age排序。
var myList = [ { Name: "Jim", Age: 20 }, { Name: "Kate", Age: 20 }, { Name: "Lilei", Age: 20 }, { Name: "John", Age: 14 }, { Name: "LinTao", Age: 25 } ]; var arrRes = Enumerable.From(myList).Distinct("x=>x.Age").ToArray();
得到的结果集合的数量为3个:[ { Name: "Jim", Age: 20 }, { Name: "John", Age: 14 }, { Name: "LinTao", Age: 25 }]。
(4)遍历:ForEach
var myList = [ { Name: "Jim", Age: 20 }, { Name: "Kate", Age: 20 }, { Name: "Lilei", Age: 20 }, { Name: "John", Age: 14 }, { Name: "LinTao", Age: 25 } ]; Enumerable.From(myList).ForEach(function(value, index){ document.write("值="+value+",索引="+index); });
很显然两个参数:一个是值,另一个是当前索引
(5)取唯一对象:First、FirstOrDefault、Last、LastOrDefault、Single、SingleOrDefault
var myList = [ { Name: "Jim", Age: 20 }, { Name: "Kate", Age: 20 }, { Name: "Lilei", Age: 20 }, { Name: "John", Age: 14 }, { Name: "LinTao", Age: 25 } ]; var arrRes = Enumerable.From(myList).FirstOrDefault("x=>x.Age>18");
其他几个用法和这个类似。这个没什么好说的。
(6)Skip、Take
Enumerable.Range(1,10).Skip(5)//结果[6,7,8,9,10] Enumerable.Range(1,10).Take(5)//结果[1,2,3,4,5]
(7)取交集、取差集、合并
var array1 = [1,412,5,3,5,412,7]; var array2 = [20,12,5,5,7,310]; Enumerable.From(array1).Except(array2) //结果3,412,1 var array1 = [1,412,5,3,5,412,7]; var array2 = [20,12,5,5,7,310]; Enumerable.From(array1).Intersect(array2) //结果5,7 var array1 = [1,412,5,3,5,412,7]; var array2 = [20,12,5,5,7,310]; Enumerable.From(array1).Union(array2) //结果是两个结果集里面所有值,并自动去重
当然还有其他一些不常用的方法。有兴趣可以查看文档。其实linq to js还有一种支持jquery的写法。如下:
Enumerable.Range(1,10).Where("$%2==0") //等价于 Enumerable.Range(1,10).Where("x=>x%2==0")
但引用文件的时候需要引用jquery.linq.js这个文件。就是写法不同,效果完全一样,选哪一种就是习惯问题了。博主更加倾向lamada方式的写法,因为和C#用法可以保持一致。
以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索c#
, 文件
, 标签
, new
, 属性
attribute
,以便于您获取更多的相关知识。