Professional ASP.NET 3.5 in C# and Visual Basic Part 58 pdf

10 434 0
Professional ASP.NET 3.5 in C# and Visual Basic Part 58 pdf

Đang tải... (xem toàn văn)

Thông tin tài liệu

Evjen c10.tex V2 - 01/28/2008 2:13pm Page 527 Chapter 10: Working with XML and LINQ to XML namespaceMgr.AddNamespace("b", "http://example.books.com") ’All books whose price is not greater than 10.00 For Each node As XPathNavigator In nav.Select( _ "//b:book[not(b:price[. > 10.00])]/b:price", namespaceMgr) Dim price As Decimal = _ CType(node.ValueAs(GetType(Decimal)), Decimal) Response.Write(String.Format("Price is {0}<BR/>", _ price)) Next C# //Load document string booksFile = Server.MapPath("books.xml"); XPathDocument document = new XPathDocument(booksFile); XPathNavigator nav = document.CreateNavigator(); //Add a namespace prefix that can be used in the XPath expression XmlNamespaceManager namespaceMgr = new XmlNamespaceManager(nav.NameTable); namespaceMgr.AddNamespace("b", "http://example.books.com"); //All books whose price is not greater than 10.00 foreach(XPathNavigator node in nav.Select("//b:book[not(b:price[. > 10.00])]/b:price", namespaceMgr)) { Decimal price = (decimal)node.ValueAs(typeof(decimal)); Response.Write(String.Format("Price is {0}<BR/>", price)); } If you then want to modify the underlying XML nodes, in the form of an XPathNavigator ,youwould use an XmlDocument instead of an XPathDocument. Your XPath expression evaluation may slow you down, but you will gain the capability to edit. Beware of this tradeoff in performance. Most often, you will want to use the read-only XPathDocument whenever possible. Listing 10-13 illustrates this change with the new or changed portions appearing in gray. Additionally, now that the document is editable, the price is increased 20 percent. Listing 10-13: Querying and editing XML with XmlDocument and XPathNodeIterator VB ’Load document Dim booksFile As String = Server.MapPath("books.xml") Dim document As New XmlDocument() document.Load(booksFile) Dim nav As XPathNavigator = document.CreateNavigator() ’Add a namespace prefix that can be used in the XPath expression Dim namespaceMgr As New XmlNamespaceManager(nav.NameTable) namespaceMgr.AddNamespace("b", "http://example.books.com") ’All books whose price is not greater than 10.00 For Each node As XPathNavigator In nav.Select( _ 527 Evjen c10.tex V2 - 01/28/2008 2:13pm Page 528 Chapter 10: Working with XML and LINQ to XML "//b:book[not(b:price[. > 10.00])]/b:price", namespaceMgr) Dim price As Decimal = CType(node.ValueAs(GetType(Decimal)), Decimal) node.SetTypedValue(price * CDec(1.2)) Response.Write(String.Format("Price raised from {0} to {1}<BR/>", _ price, _ CType(node.ValueAs(GetType(Decimal)), Decimal))) Next C# //Load document string booksFile = Server.MapPath("books.xml"); XmlDocument document = new XmlDocument(); document.Load(booksFile); XPathNavigator nav = document.CreateNavigator(); //Add a namespace prefix that can be used in the XPath expression XmlNamespaceManager namespaceMgr = new XmlNamespaceManager(nav.NameTable); namespaceMgr.AddNamespace("b", "http://example.books.com"); //All books whose price is not greater than 10.00 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); Response.Write(String.Format("Price inflated raised from {0} to {1}<BR/>", price, node.ValueAs(typeof(decimal)))); } Listing 10-13 changes the XPathDocument to an XmlDocument , and adds a call to XPathNavigator .SetTypedValue to update the price of the document in memory. The resulting document could then be persisted to storage as needed. If SetTypedValue was instead called on the XPathNavigator that was returned by XPathDocument ,a NotSupportedException would be thrown as the XPathDocument is read-only. The Books.xml document loaded from disk uses http://example.books.com as its default namespace. Because the Books.xsd XML Schema is associated with the Books.xml document, and it assigns the default namespace to be http://example.books.com , the XPath must know how to resolve that names- pace. Otherwise, you cannot determine if an XPath expression with the word book in it refers to a book from this namespace or another book entirely. An XmlNamespaceManager is created, and b is arbitrarily used as the namespace prefix for the XPath expression. Namespace resolution can be very confusing because it is easy to assume that your XML file is all alone in the world and that specifying a node named book is specific enough to enable the system to find it. However, remember that your XML documents should be thought of as living among all the XML in the world — this makes providing a qualified namespace all the more important. The XmlNamespaceManager in Listing 10-12 is passed into the call to SelectNodes in order to associate the prefix with the appropriate namespace. Remember, the namespace is unique, not the prefix; the prefix is simply a convenience acting as an alias to the longer namespace. If you find that you’re having trouble getting an XPath expression to 528 Evjen c10.tex V2 - 01/28/2008 2:13pm Page 529 Chapter 10: Working with XML and LINQ to XML work and no nodes are being returned, find out if your source XML has a namespace specified and that it matches up with a namespace in your XPath. Using XPath with XDocuments in LINQ for XML You can use XPath against an XDocument object by adding a reference to the System.Xml.XPath namespace via a using or Imports statement. Adding this reference adds new extension methods to the XDocument like CreateNavigator get to an XPathNavigator and the very useful XPathSelectElements. XPathSelectElements is similar to the SelectNodes and SelectSingleNode methods of the System.Xml .XmlDocument . These extension methods are part of the ‘‘bridge classes’’ that provide smooth integration between System.Xml and System.Xml.Linq . Listing 10-12q: Querying XDocuments with XPath Expressions VB Dim booksFile As String = Server.MapPath("books.xml") Dim document As XDocument = XDocument.Load(booksFile) ’Add a namespace prefix that can be used in the XPath expression Dim namespaceMgr As New XmlNamespaceManager(New NameTable()) namespaceMgr.AddNamespace("b", "http://example.books.com") ’All books whose price is not greater than 10.00 Dim nodes = document.XPathSelectElements( "//b:book[not(b:price[. > 10.00])]/b:price", namespaceMgr) For Each node In nodes Response.Write(node.Value + "<BR/>") Next C# //Load document string booksFile = Server.MapPath("books.xml"); XDocument document = XDocument.Load(booksFile); //Add a namespace prefix that can be used in the XPath expression. // Note the need for a NameTable. It could be new or come from elsewhere. XmlNamespaceManager namespaceMgr = new XmlNamespaceManager(new NameTable()); namespaceMgr.AddNamespace("b", "http://example.books.com"); var nodes = document.XPathSelectElements( "//b:book[not(b:price[. > 10.00])]/b:price",namespaceMgr); //All books whose price is not greater than 10.00 foreach (var node in nodes) { Response.Write(node.Value + "<BR/>"); } Notice that the added method in Listing 10-12q, XPathSelectElements , still requires an IXmlNames- paceResolver , so we create a new NameTable and map the namespaces and prefixes explicitly via XmlNamespaceManager . When using XElements and simple queries, you’re better off using LINQ to XML and the new XElement-specific methods such as Elements() and Descendants() rather than XPath. 529 Evjen c10.tex V2 - 01/28/2008 2:13pm Page 530 Chapter 10: Working with XML and LINQ to XML DataSets The System.Data namespace and System.Xml namespace have started mingling their functionality for some time. DataSets are a good example of how relational data and XML data meet in a hybrid class library. During the COM and XML heyday, the ADO 2.5 recordset sported the capability to persist as XML. The dramatic inclusion of XML functionality in a class library focused entirely on manipulation of relational data was a boon for developer productivity. XML could be pulled out of SQL Server and manipulated. Persisting DataSets to XML Classes within System.Data use XmlWriter and XmlReader in a number of places. Now that you’re more familiar with System.Xml concepts, be sure to take note of the method overloads provided by the classes within System.Data . For example, the DataSet.WriteXml method has four overloads, one of which takes in XmlWriter . Most of the methods with System.Data are very pluggable with the classes from System.Xml . Listing 10-14 shows another way to retrieve the XML from relational data by loading a DataSet from a SQL command and writing it directly to the browser with the Response object’s OutputStream property using DataSet.WriteXml . Listing 10-14: Extracting XML from a SQL Server with System.Data.DataSet VB Dim connStr As String = "database=Northwind;Data Source=localhost; " _ & "User id=sa;pwd=wrox" Using conn As New SqlConnection(connStr) Dim command As New SqlCommand("select * from customers", conn) conn.Open() Dim ds As New DataSet() ds.DataSetName = "Customers" ds.Load(command.ExecuteReader(), LoadOption.OverwriteChanges, "Customer") Response.ContentType = "text/xml" ds.WriteXml(Response.OutputStream) End Using C# string connStr = "database=Northwind;Data Source=localhost;User id=sa;pwd=wrox"; using (SqlConnection conn = new SqlConnection(connStr)) { SqlCommand command = new SqlCommand("select * from customers", conn); conn.Open(); DataSet ds = new DataSet(); ds.DataSetName = "Customers"; ds.Load(command.ExecuteReader(), LoadOption.OverwriteChanges, "Customer"); Response.ContentType = "text/xml"; ds.WriteXml(Response.OutputStream); } DataSets have a fairly fixed format, as illustrated in this example. The root node of the document is Customers , which corresponds to the DataSetName property. DataSets contain one or more named DataTable objects, and the names of these DataTables define the wrapper element — in this case, Customer . The name of the DataTable is passed into the load method of the DataSet. The correlation 530 Evjen c10.tex V2 - 01/28/2008 2:13pm Page 531 Chapter 10: Working with XML and LINQ to XML between the DataSet’s name, DataTable ’s name, and the resulting XML is not obvious when using DataSets. The resulting XML is shown in the browser in Figure 10-4. Figure 10-4 DataSets present a data model that is very different from the XML way of thinking about data. Much of the XML-style of thinking revolves around the InfoSet or the DOM, whereas DataSets are row- and column-based. The XmlDataDocument is an attempt to present these two ways of thinking into one relatively unified model. XmlDataDocument Although DataSets have their own relatively inflexible format for using XML, the XmlDocument class does not. In order to bridge this gap, an unusual hybrid object, the XmlDataDocument , is introduced. This object maintains the full fidelity of all the XML structure and allows you to access XML via the XmlDocument API without losing the flexibility of a relational API. An XmlDataDocument contains a DataSet of its own and can be called DataSet-aware. Its internal DataSet offers a relational view of the XML data. Any data contained within the XML data document that does not map into the relational view is not lost, but becomes available to the DataSet’s APIs. 531 Evjen c10.tex V2 - 01/28/2008 2:13pm Page 532 Chapter 10: Working with XML and LINQ to XML The XmlDataDocument is a constructor that takes a DataSet as a parameter. Any changes made to the XmlDataDocument are reflected in the DataSet and vice versa. Now take the DataSet loaded in Listing 10-14 and manipulate the data with the XmlDataDocument and DOM APIs you’re familiar with. Next, jump back into the world of System.Data and see that the DataSets underlying DataRows have been updated with the new data, as shown in Listing 10-15. Listing 10-15: Changing DataSets using the DOM APIs from XmlDataDocument VB Dim connStr As String = "database=Northwind;Data Source=localhost; " _ & "User id=sa;pwd=wrox" Using conn As New SqlConnection(connStr) Dim command As New SqlCommand("select * from customers", conn) conn.Open() Dim ds As New DataSet() ds.DataSetName = "Customers" ds.Load(command.ExecuteReader(), LoadOption.OverwriteChanges, "Customer") ’Response.ContentType = "text/xml" ’ds.WriteXml(Response.OutputStream) ’Added in Listing 10-15 Dim doc As New XmlDataDocument(ds) doc.DataSet.EnforceConstraints = False Dim node As XmlNode = _ doc.SelectSingleNode("//Customer[CustomerID = ’ANATR’]/ContactTitle") node.InnerText = "Boss" doc.DataSet.EnforceConstraints = True Dim dr As DataRow = doc.GetRowFromElement(CType(node.ParentNode, XmlElement)) Response.Write(dr("ContactName").ToString() & " is the ") Response.Write(dr("ContactTitle").ToString()) End Using C# string connStr = "database=Northwind;Data Source=localhost; " + "User id=sa;pwd=wrox"; using (SqlConnection conn = new SqlConnection(connStr)) { SqlCommand command = new SqlCommand("select * from customers", conn); conn.Open(); DataSet ds = new DataSet(); ds.DataSetName = "Customers"; ds.Load(command.ExecuteReader(), LoadOption.OverwriteChanges,"Customer"); //Response.ContentType = "text/xml"; //ds.WriteXml(Response.OutputStream); //Added in Listing 10-15 XmlDataDocument doc = new XmlDataDocument(ds); doc.DataSet.EnforceConstraints = false; XmlNode node = doc.SelectSingleNode(@"//Customer[CustomerID = ’ANATR’]/ContactTitle"); 532 Evjen c10.tex V2 - 01/28/2008 2:13pm Page 533 Chapter 10: Working with XML and LINQ to XML node.InnerText = "Boss"; doc.DataSet.EnforceConstraints = true; DataRow dr = doc.GetRowFromElement((XmlElement)node.ParentNode); Response.Write(dr["ContactName"].ToString() + " is the "); Response.Write(dr["ContactTitle"].ToString()); } Listing 10-15 extends Listing 10-14 by first commenting out changing the HTTP ContentType and the call to DataSet.WriteXml . After the DataSet is loaded from the database, it is passed to the XmlDataDocument constructor. At this point, the XmlDataDocument and the DataSet refer to the same set of information. The EnforceConstraints property of the DataSet is set to false to allow changes to the DataSet. When EnforceConstraints is later set to true , if any constraint rules were broken, an exception is thrown. An XPath expression is passed to the DOM method SelectSingleNode , selecting the ContactTitle node of a particular customer, and its text is changed to Boss . Then by calling GetRowFromElement on the XmlDataDocument , the context jumps from the world of the XmlDocument back to the world of the DataSet. Column names are passed into the indexing property of the returned DataRow ,andtheoutput is shown in this line: Ana Trujillo is the Boss The data is loaded from the SQL server and then manipulated and edited with XmlDocument -style methods; a string is then built using a DataRow from the underlying DataSet. XML is clearly more than just angle brackets. XML data can come from files, from databases, from information sets like the DataSet object, and certainly from the Web. Today, however, a considerable amount of data is stored in XML format, so a specific data source control has been added to ASP.NET 2.0 just for retrieving and working with XML data. The XmlDataSource Control The XmlDataSource control enables you to connect to your XML data and to use this data with any of the ASP.NET data-bound controls. Just like the SqlDataSource and the AccessDataSource controls, the XmlDataSource control also enables you not only to retrieve data, but also to insert, delete, and update data items. One unfortunate caveat of the XmlDataSource is that its XPath attribute does not support documents that use namespace qualification. Examples in this chapter use the Books.xml file with a default namespace of http://examples.books.com .Itis very common for XML files to use multiple namespaces, including a default namespace. As you learned when you created an XPathDocument and queried it with XPath, the namespace in which an element existsisveryimportant.Theregrettable reality is, there is no way to use a namespace qualified XPath expression or to make the XmlDataSource Control aware of a list of prefix/namespace pairs via the XmlNamespaceManager class. However, the XPath function used in the ItemTemplate of the templated DataList control can take a XmlNamespaceManager as its second parameter and query XML returned from the XmlDataSource —aslongasthe control does not include an XPath attribute with namespace qualification or you can 533 Evjen c10.tex V2 - 01/28/2008 2:13pm Page 534 Chapter 10: Working with XML and LINQ to XML just omit it all together. That said, in order for these examples to work, you must remove the namespaces from your source XML and use XPath queries that include no namespace qualification, as shown in Listing 10-16. You can use a DataList control or any DataBinding-aware control and connect to an < asp: XmlDataSource > control. The technique for binding a control directly to the Books.xml file is illustrated in Listing 10-16. Listing 10-16: Using a DataList control to display XML content <%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="Default_aspx" %> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <title>XmlDataSource</title> </head> <body> <form id="form1" runat="server"> <asp:datalist id="DataList1" DataSourceID="XmlDataSource1" runat="server"> <ItemTemplate> <p><b><%# XPath("author/first-name") %> <%# XPath("author/last-name")%></b> wrote <%# XPath("title") %></p> </ItemTemplate> </asp:datalist> <asp:xmldatasource id="XmlDataSource1" runat="server" datafile="~/Books.xml" xpath="//bookstore/book"/> </form> </body> </html> This is a simple example, but it shows you the ease of using the XmlDataSource control. You should focus on two attributes in this example. The first is the DataFile attribute. This attribute points to the location of the XML file. Because the file resides in the root directory of the application, it is simply ∼ /Books.xml . The next attribute included in the XmlDataSource control is the XPath attribute. The XmlDataSource control uses the XPath attribute for the filtering of XML data. In this case, the XmlDataSource control is taking everything within the < book > set of elements. The value //bookstore/book means that the XmlDataSource control navigates to the < bookstore > element and then to the < book > element within the specified XML file and returns a list of all books. The DataList control then must specify its DataSourceID as the XmlDataSource control. In the < ItemTemplate > section of the DataList control, you can retrieve specific values from the XML file by using XPath commands within the template. The XPath commands filter the data from the XML file. The first value retrieved is an element attribute ( author/first-name ) that is contained in the < book > element. If you are retrieving an attribute of an element, you preface the name of the attribute with an at ( @ ) symbol. The next two XPath commands get the last name and the title of the book. Remember 534 Evjen c10.tex V2 - 01/28/2008 2:13pm Page 535 Chapter 10: Working with XML and LINQ to XML to separate nodes with a forward slash ( / ). When run in the browser, this code produces the results illustrated in the following list: Benjamin Franklin wrote The Autobiography of Benjamin Franklin Herman Melville wrote The Confidence Man Sidas Plato wrote The Gorgias Note that if you wrote the actual code, this entire exercise would be done entirely in the ASPX page itself! Besides working from static XML files such as the Books.xml file shown earlier, the XmlDataSource control has the capability to work from dynamic, URL-accessible XML files. One popular XML format that is pervasive on the Internet today is the weblog.Theseblogs, or personal diaries, can be viewed either in the browser, through an RSS-aggregator, or as pure XML. In Figure 10-5, you can see the XML from my blog’s RSS feed. I’ve saved the XML to a local file and removed a stylesheet so I can see what the XML looks like when viewed directly in the browser. (You can find a lot of blogs to play with for this example at weblogs.asp.net. ) Figure 10-5 535 Evjen c10.tex V2 - 01/28/2008 2:13pm Page 536 Chapter 10: Working with XML and LINQ to XML Now that you know the location of the XML from the blog, you can use this XML with the XmlDataSource control and display some of the results in a DataList control.Thecodeforthisexampleisshownin Listing 10-17. Listing 10-17: Displaying an XML RSS blog feed <%@ Page Language="VB"%> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>XmlDataSource</title> </head> <body> <form id="form1" runat="server"> <asp:DataList ID="DataList1" Runat="server" DataSourceID="XmlDataSource1"> <HeaderTemplate> <table border="1" cellpadding="3"> </HeaderTemplate> <ItemTemplate> <tr><td><b><%# XPath("title") %></b><br /> <i><%# XPath("pubDate") %></i><br /> <%# XPath("description") %></td></tr> </ItemTemplate> <AlternatingItemTemplate> <tr bgcolor="LightGrey"><td><b><%# XPath("title") %></b><br /> <i><%# XPath("pubDate") %></i><br /> <%# XPath("description") %></td></tr> </AlternatingItemTemplate> <FooterTemplate> </table> </FooterTemplate> </asp:DataList> <asp:XmlDataSource ID="XmlDataSource1" Runat="server" DataFile="http://www.hanselman.com/blog/feed" XPath="rss/channel/item"> </asp:XmlDataSource> </form> </body> </html> Looking at the code in Listing 10-17, you can see that the DataFile points to a URL where the XML is retrieved. The XPath property filters and returns all the < item > elements from the RSS feed. The DataList control creates an HTML table and pulls out specific data elements from the RSS feed, such as the < title >, < pubDate >,and< description > elements. Running this page in the browser, you get something similar to the results shown in Figure 10-6. This approach also works with XML Web services, even ones for which you can pass in parameters using HTTP-GET. You just set up the DataFile property value in the following manner: DataFile="http://www.someserver.com/GetWeather.asmx/ZipWeather?zipcode=63301" 536 . XmlDataDocument(ds); doc.DataSet.EnforceConstraints = false; XmlNode node = doc.SelectSingleNode(@"//Customer[CustomerID = ’ANATR’]/ContactTitle"); 53 2 Evjen c10.tex V2 - 01/28/2008 2:13pm Page 53 3 Chapter 10: Working with XML and. namespace qualification or you can 53 3 Evjen c10.tex V2 - 01/28/2008 2:13pm Page 53 4 Chapter 10: Working with XML and LINQ to XML just omit it all together. That said, in order for these examples to. 2:13pm Page 53 5 Chapter 10: Working with XML and LINQ to XML to separate nodes with a forward slash ( / ). When run in the browser, this code produces the results illustrated in the following

Ngày đăng: 05/07/2014, 18:20

Từ khóa liên quan

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan