.net XML 使用

Xml文件 Books.xml
<?xml version="1.0" encoding="utf-8" ?>
<bookstore xmlns="http://example.books.com">
  <book genre="autobiography" publicationdate="1991" ISBN="1-861003-11-0">
    <title>The Autobiography of Benjamin Franklin</title>
    <author>
      <first-name>Benjamin</first-name>
      <last-name>Franklin</last-name>
    </author>
    <price>8.99</price>
  </book>
  <book genre="novel" publicationdate="1967" ISBN="0-201-63361-2">
    <title>The Confidence Man</title>
    <author>
      <first-name>Herman</first-name>
      <last-name>Melville</last-name>
    </author>
    <price>11.99</price>
  </book>
  <book genre="philosophy" publicationdate="1991" ISBN="1-861001-57-6">
    <title>The Gorgias</title>
    <author>
      <name>Plato</name>
    </author>
    <price>9.99</price>
  </book>
</bookstore>

后台代码页C#
using System;
using System.IO;
using System.Xml;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        int bookcount = 0;
        XmlReaderSettings settings = new XmlReaderSettings();

        settings.IgnoreWhitespace = true;
        settings.IgnoreComments = true;

        string booksFile = Server.MapPath("Books.xml");
        using (XmlReader reader = XmlReader.Create(booksFile, settings))
        {
            while (reader.Read())
            {
                if (reader.NodeType == XmlNodeType.Element && reader.LocalName == "book")
                {
                    bookcount++;
                }
            }
        }
    }
}

这里使用了XmlReader.Create方法,它可以用于创建XmlReader的具体实现代码,但如果采用这种技术,就会发现它非常灵活,因为可以在创建XmlReader的其他实例时重用XmlSettings对象,因为XmlReader实现了IDisposable,所以Using关键字使用
从XmlReader的观点来看,所有的东西都是节点,包括 空白、注释、属性、元素和结束元素
提示:
Reader.LocalName属性包含节点的非名称空间限定名。Reader.Name属性与它不同,它包含节点的完全限定名(包括命名空间)

---------------------------------
使用XDocument 替代XmlReader
System.Xml.Linq命名空间引入了一个心累XDocument,类似Ling的查询语法

using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        XDocument booksXML = XDocument.Load(Server.MapPath("Books.xml"));
        var books = from book in 
                        booksXML.Descendants("{http://sample.books.com}book")
                        select book.Element("{http://sample.books.com}title").Value;
    }
}

无论XML文档的模式如何,第一段代码中如果文档包含book元素,代码就会给它计数。如果代码之对特定模式类型的图书进行技术,这里是指Books.xml文件中的图书,就根据Books.xsd模式进行验证
XmlReaderSettings settings = new XmlReaderSettings();

        string booksSchemaFile = Server.MapPath("booksSchemaFile");

        settings.Schemas.Add(null,XmlReader.Create(booksSchemaFile));
        settings.ValidationType = ValidationType.Schema;
        settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings;
        settings.ValidationEventHandler += new ValidationEventHandler(settings_ValidationEventHandler);

包含NameTable优化
     XmlReader内部使用NameTable,列出该文档中使用的所有已知的元素、属性和命名空间,这个过程称为原子化,其字面意思是XML文档被分解为各个原子部分。如果把字符串book作为一个对象引用,和其他元素名一起保存在一个表中,就不需要把book在内部结构中存储多次。
    这是一个内部实现细节,但它是一种得到支持的有效方式,可以大大加速XML类的使用,泪如XmlReader 和 XmlDocument。吧name元素添加到NameTable中,使用字符串比较,来比较字符串字面值 和 reader.LoaclName。这些比较还可以转换对象引用比较,对象引用比较比字符串比较快许多,从而得到优化。另外,XML NameTable可以在System.Xml类的多个实例中共享,甚至在XmlReaders和XmlDocuments之间共享。
    因为我们正在计算book元素的个数,所以创建一个包含该元素(book)的NameTable,另外我们并不比较字符串,而是比较兑现给引用
 protected void Page_Load(object sender, EventArgs e)
    {
        int bookcount = 0;
        XmlReaderSettings settings = new XmlReaderSettings();
        NameTable nt = new NameTable();
        object book = nt.Add("book");

        settings.NameTable = nt;

        string booksSchemaFile = Path.Combine(Request.PhysicalApplicationPath,"books.xsd");
        settings.Schemas.Add(null, XmlReader.Create(booksSchemaFile));
        settings.ValidationType = ValidationType.Schema;
        settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings;
        settings.ValidationEventHandler += new ValidationEventHandler(settings_ValidationEventHandler);

        settings.IgnoreComments = true;
        settings.IgnoreWhitespace = true;

        string booksFile = Path.Combine(Request.PhysicalApplicationPath,"books.xml");
        using (XmlReader reader = XmlReader.Create(booksFile))
        {
            while (reader.Read())
            {
                if (reader.NodeType == XmlNodeType.Element &&
                    book.Equals(reader.LocalName))
                {
                    bookcount++;
                }
            }
        }
    }

    NameTable被添加到XmlSettings对象中,NameTable的Add方法返回对钢材添加的原子的对象引用,在这里,该原子存储在对象引用book中,以后book引用将用于比较reader.LoaclName属性。这里选择使用.NET Framework中所有对象都有的Equals方法,以强调这是检查对象的相等性。这两个对象要么是同一个额原子,要么不是。在NameTable上从Add方法返回的book,对象与分析XML文档 Books.xml中的book元素时读取器使用的对象相同。
    在上例中,给非常少量的图书技术,但对于接近1MB的大型XML来说,性能会提升10%-15%,尤其是涉及到XmlReader的计算和处理时,性能的提升更明显。另外,由于NameTable高速缓存在XmlReaderSettings对象中,所以在XmlReaderSettings兑现给重用于其他System.Xml对象时,也会重用NameTable,这将再次提升性能。

---------------------------------
从XML中体书.NET CLR类型
 protected void Page_Load(object sender, EventArgs e)
    {
        int bookcount = 0;
        decimal booktotal = 0;
        XmlReaderSettings settings = new XmlReaderSettings();
        string booksSchemFile = Path.Combine(Request.PhysicalApplicationPath,"books.xsd");
        NameTable nt = new NameTable();
        object book=nt.Add("book");
        object price = nt.Add("price");

        settings.NameTable = nt;
        string booksFile = Path.Combine(Request.PhysicalApplicationPath,"Books.xml");

        using (XmlReader reader = XmlReader.Create(booksFile, settings))
        {
            while (reader.Read())
            {
                if (reader.NodeType == XmlNodeType.Element &&
                    book.Equals(reader.LocalName))
                {
                    bookcount++;
                }
                if (reader.NodeType == XmlNodeType.Element &&
                    price.Equals(reader.LocalName))
                {
                    booktotal += reader.ReadElementContentAsDecimal();
                }
            }
        }
    }

上例中的booktotal变量被强类型化为一个小数值
----------------------------------
ReadSubtree 和XmlSerialization
     XmlReader不仅可以从XML中提取简单类型,还可以是哟娜韩国XML串行化和ReadSubtree提取更复杂的类型
    XML串行化器可以给已有的类添加属性,为XML串行化器提供如何把对象标识为XML的提示。XML串行化器只能串行化对象的公共属性,不能串行化私有属性。
    在创建XmlSerializer时,要把一个Type对象传入构造函数,XmlSerializer就会使用反射检查该对象是否能创建一个临时的程序集,该程序集知道如何把对象读写为XML。XmlSerializer使用XmlReader内部的一个具体实现方式来串行化这些对象。
    下列中使用ReadSubtree和一个新的类型化Author类,该类已是哟还能够XML串行化属性进行了标记,ReadSubtree会在当前位置分解一个新的XmlReader,该XmlReader传送给XmlSerializer,并创建一个复杂类型。Author类包含XmlElement属性,它表示尽管有一个FirstName属性,但它应该串行化和反串行化为“姓”
using System.Xml.Serialization;
[XmlRoot(ElementName="author",Namespace="http://example.books.com")]
public class Author
{
    [XmlElement(ElementName = "first-name")]
    public string FirstName;

    [XmlElement(ElementName = "last-name")]
    public string LastName;
}

 XmlSerializerFactory factory = new XmlSerializerFactory();

        using (XmlReader reader = XmlReader.Create(booksFile, settings))
        {
            while (reader.Read())
            {
                if (reader.NodeType == XmlNodeType.Element &&
                    book.Equals(reader.LocalName))
                {
                    XmlSerializer xs = factory.CreateSerializer(typeof(Author));
                    Author a = (Author)xs.Deserialize(reader.ReadSubtree());
                }
            }
        }

-----------------------------
通过LINQ to XML 从 XML中创建CLR对象
     在XmlSerialize和System.Xml.Linq之间没有直接的关联,但有一种非常简单的方法可以在LINQ to XML语法中创建CLR对象。这个语法比传统的XmlSerializer更灵活、宽泛,如下程序所示
    
XDocument booksXML = XDocument.Load(Server.MapPath("Books.xml"));
        XNamespace ns = "http://sample.books.com";

        var authros = from book in booksXML.Descendants(ns + "author")
                      select new Author
                      {
                          FirstName = book.Element(ns + "first-name").Value,
                          LastName = book.Element(ns + "last-name").Value
                      };

--------------------------------------------
用XmlWriter创建XML 
     XmlWriter的工作方式类似XmlReader,但顺序相反,使用字符床连接来快速创建XML文档,或XML片段时非常吸引人的,但XML是InfoSet的表示,不是尖括号
    XmlWriter还有一个设置类XmlWriterSettings。这个类包含缩进、换行、编码、XML一致级别等选项。在下列中创建了一个XML文档bookstore,并把它直接输出到页面上。ASPX页面上的所有HTML标记都必须删除,这样才能正确输出XML文档。输出XML的另一种简单方式是使用ASHX HttpHandler
protected void Page_Load(object sender, EventArgs e)
    {
        Double price = 49.99;
        DateTime publicationdate = new DateTime(2005,1,1);
        String isbn = "1-057-610-0";
        Author a = new Author();
        a.FirstName = "Scott";
        a.LastName = "Hanselman";

        XmlWriterSettings settings = new XmlWriterSettings();
        settings.Indent = true;
        settings.NewLineOnAttributes = true;

        Response.ContentType = "text/xml";

        XmlSerializerFactory factory = new XmlSerializerFactory();

        using (XmlWriter writer = XmlWriter.Create(Response.OutputStream, settings))
        {
            writer.WriteStartDocument();
                writer.WriteStartElement("bookstore");
                    writer.WriteStartElement("book");
                        writer.WriteStartAttribute("publicationdate");
                            writer.WriteValue(publicationdate);
                        writer.WriteEndAttribute();
                        writer.WriteStartAttribute("ISBN");
                        writer.WriteValue(isbn);
                        writer.WriteEndAttribute();
                        writer.WriteElementString("title","ASP.NET");
                        writer.WriteStartAttribute("price");
                        writer.WriteValue(price);
                        writer.WriteEndAttribute();
                        XmlSerializer xs = factory.CreateSerializer(typeof(Author));
                        xs.Serialize(writer, a);
                    writer.WriteEndElement();
                writer.WriteEndElement();
            writer.WriteEndDocument();
        }
    }

----------------------------------------
使用LINQfor XML 创建XML
使用LINQ for XML不如XmlWrite快,但仍非常快,切非常容易阅读。
Double price = 49.99;
        DateTime publicationdate = new DateTime(2005,1,1);
        String isbn = "1-057-610-0";
        Author a = new Author();
        a.FirstName = "Scott";
        a.LastName = "Hanselman";

        Response.ContentType = "text/xml";
        XNamespace ns = "http://sample.books.com";

        XDocument books = new XDocument(
            new XElement(ns+"bookstore",
                new XElement(ns+"book"),
                new XAttribute("publicationdate",publicationdate),
                    new XAttribute("ISBN",isbn),
                    new XElement(ns +"title","ASP.net"),
                    new XElement(ns+"price",price),
                    new XElement(ns+"author",
                        new XElement(ns+"first-name",a.FirstName),
                        new XElement(ns+"last-name",a.LastName)
                        )
                    )
            );

----------------
使用XPathDocumnet,下例找出价格低于10美元的图书
XPahtDocument 把一个 XPathNavigator作为调用CreateNavigator的结果。XPathNavigator使用一个传送给Select方法的XPath来查询,并返回一个XPathNodeIterator。该XPathNodeIterator可以通过IEnumberable来遍历。例子使用了一个制度XPathDocument,并没有更新内存中的数据
tring booksFile = Server.MapPath("Books.xml");
        
        XPathDocument document = new XPathDocument(booksFile);
        XPathNavigator nav = document.CreateNavigator();

        XmlNamespaceManager namespaceMgr = new XmlNamespaceManager(nav.NameTable);
        namespaceMgr.AddNamespace("b", "http://sample.books.com");

        foreach(XPathNavigator node in 
            nav.Select("//b:book[not(b:price[. > 10.00])]/b:price)",namespaceMgr))
            {
                Decimal price = (decimal)node.ValueAs(typeof(decimal));
            }

如果要以XPathNavigator的形式修改底层的XML节点,就应该使用XmlDocument代替XPathDocument.XPath表达式的计算可能比较慢,但应该可以编辑。注意它在性能上的妥协。在大多数情况下,应尽可能使用只读的XPathDocument;如下修改
string booksFile = Server.MapPath("Books.xml");

        XmlDocument document = new XmlDocument();
        document.Load(booksFile);
        XPathNavigator nav = document.CreateNavigator();

        XmlNamespaceManager namespaceMgr = new XmlNamespaceManager(nav.NameTable);
        namespaceMgr.AddNamespace("b", "http://sample.books.com");

        foreach(XPathNavigator node in 
            nav.Select("//b:book[not(b:price[. > 10.00])]/b:price)",namespaceMgr))
            {
                Decimal price = (decimal)node.ValueAs(typeof(decimal));
                node.SetTypedValue(price * 1.2M);
            }

-------------------------
将DataSet 保存到XML中
string cnnStr = "database=Northwind;Data Source=localhost;User id=sa;pwd=sa";
        using (SqlConnection conn = new SqlConnection(cnnStr))
        {
            SqlCommand command = new SqlCommand("select * from customers",conn);
            conn.Open();
            DataSet ds = new DataSet();
            ds.DataSetName = "Customers";
            ds.Load(command.ExecuteReader(), LoadOption.OverwriteChanges, "Customers");
            Response.ContentType = "text/xml";
            ds.WriteXml(Response.OutputStream);
        }

XmlDataDocument
    DataSet使用XML时的格式不太灵活,但XmlDocument类不是这样。为了在它们之间架起桥梁,引入了一个不太常见的混合对象XmlDataDocument. 这个对象保留了所有的XML结构,可以通过XmlDocument API访问XML,切不会丧失关系API的灵活性。XmlDataDocument包含它自己的DataSet,可以称为支持DataSet。它的内部DataSet提供了XML数据的关系视图。包含在XML数据文档中,切没有映射到关系视图上的所有数据都不会丢失,而且这写数据可以用于DataSet的API。
    XmlDataDocument是一个构造函数,它把DataSet作为一个参数。对XmlDataDocument的任何修改都会反映到DataSet上,反之亦然。
string cnnStr = "database=Northwind;Data Source=localhost;User id=sa;pwd=sa";
        using (SqlConnection conn = new SqlConnection(cnnStr))
        {
            SqlCommand command = new SqlCommand("select * from customers",conn);
            conn.Open();
            DataSet ds = new DataSet();
            ds.DataSetName = "Customers";
            ds.Load(command.ExecuteReader(), LoadOption.OverwriteChanges, "Customers");

            XmlDataDocument doc = new XmlDataDocument(ds);
            doc.DataSet.EnforceConstraints = false;
            XmlNode node = doc.SelectSingleNode(@"//Customer[CustomerID='ANATR']/ContatcTitle");
            node.InnerText="Boss";
            doc.DataSet.EnforceConstraints = true;

            Response.ContentType = "text/xml";
            ds.WriteXml(Response.OutputStream);
        }

DataSet 的属性 EnforceConstraints被设置为false,以允许修改DataSet。

-----------------------------------------
数据库和XML
     XML可以来自于任何数据源,SQL Server 和ADO都支持XML,例如System.Data.SqlCommand类的ExectuteXmlReader方法。在SQL Server2000上对XML的支持包括SQLXML3.0 机器XML扩展,SQL Server2005 内置了对XML数据类型的支持,
    可以使用FOR XML AUTO 子句修改SQL 查询,使之返回XML。如果有一个简单的查询,如 select * from customers 就可以修改语句,如下所示
select * from customers as customer FOR XML AUTO
    XML AUTO 返回XML片段,而不是带有文档元素的完整XML文档。数据库中的每一行都将成为一个元素,数据库中的每一列都将成为元素上的一个属性。

<customers CustomerID="ALFKI" CompanyName="Alfreds Futterkiste" ContactName="Maria Anders" ContactTitle="Sales Representative" Address="Obere Str. 57" City="Berlin" PostalCode="12209" Country="Germany" Phone="030-0074321" Fax="030-0076545"/><customers CustomerID="ANATR" CompanyName="Ana Trujillo Emparedados y helados" ContactName="Ana Trujillo" ContactTitle="Owner" Address="Avda. de la Constitución 2222" City="México D.F." PostalCode="05021" Country="Mexico" Phone="(5) 555-4729" Fax="(5) 555-3745"/>

   如果 select * from customers FOR XML AUTO,ELEMENTS 

<customers><CustomerID>ALFKI</CustomerID><CompanyName>Alfreds Futterkiste</CompanyName><ContactName>Maria Anders</ContactName><ContactTitle>Sales Representative</ContactTitle><Address>Obere Str. 57</Address><City>Berlin</City><PostalCode>12209</PostalCode><Country>Germany</Country><Phone>030-0074321</Phone><Fax>030-0076545</Fax></customers><customers><CustomerID>ANATR</CustomerID><CompanyName>Ana Trujillo Emparedados y helados</CompanyName><ContactName>Ana Trujillo</ContactName><ContactTitle>Owner</ContactTitle><Address>Avda. de la Constitución 2222</Address><City>México D.F.</City><PostalCode>05021</PostalCode><Country>Mexico</Country><Phone>(5) 555-4729</Phone><Fax>(5) 555-3745</Fax></customers>
下面的示例是一个返回定制XML的查询,查询开头的WITH NAMESPACES定义了一个默认的命名空间,并使用列样式别名将命名空间与命名空间前缀关联起来。在这个示例中,addr:shi urn:hanselman.com/northwind/address 的前缀
WITH XMLNAMESPACES(	'urn:hanselman.com/norhtwind/address' as addr,
	DEFAULT 'nrn:hanselman.com/northwind')
SELECT CustomerID as 'ID',
	CompanyName,
	Address as 'addr:Address/addr:Street',
	City as 'addr:Address/addr:City',
	Region as 'addr/Address/addr:Region',
	PostalCode as 'addr:Address/addr:Zip',
	Country as 'addr:Address/addr:Country',
	ContactName as 'Contact/Name',
	Phone as 'Contact/Phone',
	Fax as 'Contact/Fax'
FROM Customers
FOR XML PATH('Customer'),ROOT('Customers'),ELEMENTS XSINIL


用AS官方尖子生名的别名描述了元素及其嵌套关系,而PATH关键字定义了Customers表示的元素。ROOT关键字定义了文档的根元素。
    ELE<ENTS关键字和XSINIL描述了处理null的方式,没有这些关键字,就不能为行中包含null的列创建XML元素。如果数据库中没有这些数据,就会使得到的XML文档缺失数据。有了ELEMENTS和XSINIL元素就能显示的 xsi:nil 语法输出。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值