您的位置:首页 > 编程语言 > C#

C#操作XML(三)

2015-06-15 15:51 344 查看
C#进入3.0时代,引入了强大的LINQ,同时提供了Linq to Xml,这个全新的Xml Api。与Inq to Xml相比,传统的DOM Api就显得笨重而繁杂了。

一、Linq to Xml的本质

  首先,Linq to Xml是一种in-memory的技术,也就是说,如果用Linq to Xml去打开一个Xml,也就会占用相应的内存。所以和DOM一样,在极端的情况下,会出现内存不足。

  其次,Linq to Xml从本质上来说,就是Linq to Object+一套Xml Api,与Linq to Sql和Linq to entity framework不同,后两者是使用特定的Linq Provider去翻译成对应系统的语言。

  Linq to Xml和DOM都是用in-memory的方式操作Xml的。

二、使用Linq to Xml操作无Namespace的Xml.

1. 创建Xml

  创建如下Xml:

<?xml version="1.0" encoding="utf-8" ?>
<persons>
<person>
<firstName>Zhenway</firstName>
<lastName>Yan</lastName>
<address>http://www.baidu.com/</address>
</person>
<person>
<firstName>Allen</firstName>
<lastName>Lee</lastName>
<address>http://www.baidu.com/</address>
</person>
</persons>


  C#代码:

    方法1:

XDocument doc = new XDocument(
new XDeclaration("1.0", "UTF-8", null),
new XElement("persons",
new XElement("person",
new XElement("firstName", "Zhenway"),
new XElement("lastName", "Yan"),
new XElement("address", "http://www.baidu.com/")
),
new XElement("person",
new XElement("firstName", "Allen"),
new XElement("lastName", "Lee"),
new XElement("address", "http://www.baidu.com/")
)
)
);


    方法2:

var persons = new[]
{
new
{
FirstName = "Zhenway",
LastName = "Yan",
Address = "http://www.baidu.com/"
},
new
{
FirstName = "Allen",
LastName = "Lee",
Address = "http://www.baidu.com//"
}
};

XDocument doc = new XDocument(
new XDeclaration("1.0", "UTF-8", null),
new XElement("persons",
from person in persons
select new XElement("person",
new XElement("firstName", person.FirstName),
new XElement("lastName", person.LastName),
new XElement("address", person.Address))
)
);


2. 查询Xml

  a. 一个简单的查询

XDocument doc = XDocument.Parse(@"<?xml version=""1.0"" encoding=""utf-8""?>
<persons>
<person>
<firstName>Zhenway</firstName>
<lastName>Yan</lastName>
<address>http://www.cnblogs.com/</address>
</person>
<person>
<firstName>Allen</firstName>
<lastName>Lee</lastName>
<address>http://www.cnblogs.com/</address>
</person>
</persons>");
foreach (var item in doc.Root.Descendants("address"))
{
Console.WriteLine((string)item);
}


  注意:Desendats方法的签名:public IEnumerable<XElement> Descendants(XName name);

     参数类型是XName,而传入的是一个string,为什么合法呢?来看一下XName中的一个定义:

     public static implicit operator XName(string expandedName);

     原来有一个隐式转换,这样就好理解了,编译器自动调用了隐式转换。

  b. 一个复杂的查询

  查询firstName为“Zhenway”的person节点中的address节点:

XDocument doc = XDocument.Parse(@"<?xml version=""1.0"" encoding=""utf-8""?>
<persons>
<person>
<firstName>Zhenway</firstName>
<lastName>Yan</lastName>
<address>http://www.cnblogs.com/</address>
</person>
<person>
<firstName>Allen</firstName>
<lastName>Lee</lastName>
<address>http://www.cnblogs.com/</address>
</person>
</persons>");
foreach (var item in from person in doc.Root.Descendants("person")
where (string)person.Element("firstName") == "Zhenway"
select (string)person.Element("address"))
{
Console.WriteLine((string)item);
}


三、使用Linq to Xml操作有Namespace的Xml

1. 设置目标

  目标:创建一个这样的Xml:

<?xml version="1.0" encoding="utf-8" ?>
<v:persons xmlns:v="http://www.cnblogs.com/">
<v:person>
<v:firstName>Zhenway</v:firstName>
<v:lastName>Yan</v:lastName>
<v:address>http://www.cnblogs.com/</v:address>
</v:person>
</v:persons>


  注意:这个Xml的每一个节点都是在http://www.cnblogs.com/这个命名空间下。

  关于Xml的命名空间也有很多种等效写法,具体请参考w3schools。

2. 分析实现手段

  a. 这里的"persons"不再是一个纯粹的"persons",而是一个带有Namespace的persons,需要修改成带有Namespace的节点名。

  b. 那么如何获得这个带有Namesapce的节点名呢?

    让我们回过头来看看XElement的构造函数:

   public XElement (XName name);

   注意:参数的类型是XName,而不是string,那么平时为什么能用string呢?因为上一篇里面提到过,XName定义了一个隐式类型转换,可以把string隐式转换为XName。

   同理,关于Namespace自然也要从XNamespace入手,然后找一个能够变成XName的方法,查看XNamespace的定义,就可以看到:

    public static XName operator +(XNamespace ns, string localName);

    只要把XNamespace加上本地名称(string),就可以是一个XName了,非常简单。

    再看看如何创建一个XNamespace:

    public static implicit operator XNamespace(string namespaceName);

   又是隐式转换...来看看具体如何创建一个带有namespace的persons吧:  

XNamespace v = "http://www.cnblogs.com/";
var persons = new XElement(v + "persons");


   定义一个namespace,在使用时直接+string即可。在C#里面这已经是最简单的方式了。

3. 创建Xml

  实现:  

XNamespace v = "http://www.cnblogs.com/";
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement(v + "persons",
new XElement(v + "persons",
new XElement(v + "firstName", "Zhenway"),
new XElement(v + "lastName", "Yan"),
new XElement(v + "address", "http://www.cnblogs.con/")
)
)
);
doc.Save(Console.Out);


  结果:

<?xml version="1.0" encoding="gb2312"?>
<persons xmlns="http://www.cnblogs.comh/">
<person>
<firstName>Zhenway</firstName>
<lastName>Yan</lastName>
<address>http://www.cnblogs.com/</address>
</person>
</persons>


  和预期的略有不同,首先encoding被修改成gb2312,这是因为中文操作系统的Console的编码是gb2312,所以Xml的encoding被自动修改了,其次,原来的Namespace用v来缩写,但是输出的xml缺是改用了默认Namespace,不过如果看过前面提到的w3schools的话,就知道这两者是等价xml。

4. 查询Xml

  在查找一个Xml时,同样也需要一个XName,因此当遇到带Namespace的Xml,也可以用同样的手法:  

XDocument doc = XDocument.Parse(@"<?xml version=""1.0"" encoding=""utf-8"" ?>
<v:persons xmlns:v=""http://www.cnblogs.com/"">
<v:person>
<v:firstName>Zhenway</v:firstName>
<v:lastName>Yan</v:lastName>
<v:address>http://www.cnblogs.com/</v:address>
</v:person>
<v:person>
<v:firstName>Allen</v:firstName>
<v:lastName>Lee</v:lastName>
<v:address>http://www.cnblogs.com/</v:address>
</v:person>
</v:persons>");
XNamespace v = "http://www.cnblogs.com/";
foreach (var item in from person in doc.Root.Descendants(v + "person")
where (string)person.Element(v + "firstName") == "Zhenway"
select (string)person.Element(v + "address"))
{
Console.WriteLine(item);
}


四、总结

  无论是DOM Api还是Linq to Xml都是In-Memory的工作方式,这样的工作方式对内存的要求相对较高,而且不适合超大Xml文件的处理(会导致内存溢出)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: