1. Trang chủ
  2. » Công Nghệ Thông Tin

Tài liệu ASP.NET 1.1 Insider Solutions- P10 docx

50 389 0

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

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Working with XML Data in ASP.NET 1.1
Trường học University of Science and Technology of Hanoi
Chuyên ngành Information Technology
Thể loại lecture notes
Năm xuất bản 2003
Thành phố Hanoi
Định dạng
Số trang 50
Dung lượng 782,38 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Each class has unique pros and cons, as outlined earlier in this LISTING 11.6 Continued Using ADO.NET to Search, Filter, and Sort XML Data You can also search, filter, and sort XML data

Trang 1

When the XML within the string is loaded into the StringReaderinstance (which is in turnpassed to the XmlTextReaderconstructor), it can be parsed like any other XML data Because theXmlTextReaderinstance is closed, theStringReaderwill automatically be closed as well.

Accessing XML Resources by Using the

The System.Xmlnamespace contains an abstract class named XmlResolverthat is responsible forresolving external resources, including items such as document type definitions (DTDs) andschemas Although a concrete instance of the XmlResolverclass can’t be created, XmlResolverhastwo child classes that derive from it—XmlUrlResolverand XmlSecureResolver—that can be instan-tiated and used These classes are used under the covers by different NET Framework classes,such as XmlDocument, XmlDataDocument, and XmlTextReader, and they can be accessed through theirrespective XmlResolverproperties

XmlUrlResolveris typically used when an external resource such as a DTD needs to be ignored,when security credentials need to be passed to a remote resource, or with XSLT stylesheets.Ignoring external resources is accomplished by setting the XmlResolverproperty of XML classessuch as XmlTextReaderand XmlDocumentto Nothing(nullin C#) This can be useful when the XMLdata needs to be parsed but a referenced DTD or schema doesn’t need to be resolved

An example of setting the XmlResolverproperty to Nothingis shown in Listing 11.2, where theMoreOver.com news feed is parsed to extract news headlines Because the DTD referenced in thedocument isn’t of use to the application, the XmlTextReaderclass’s XmlResolverproperty is set toNothing If the XmlResolverproperty were left in its default state, the DTD uniform resource iden-tifier (URI) would be resolved by an underlying XmlResolverproperty, assuming that access to theInternet is available However, if a proxy server blocked outside access to the DTD or if thenetwork were temporarily unavailable, the following error would occur:

The underlying connection was closed:

The remote name could not be resolved

You can also use the XmlUrlResolverclass to pass security credentials to a remote resource thatrequires authentication by using its Credentialsproperty Credentialsrepresents a write-onlyproperty of type ICredentials Listing 11.5 shows how you can create an XmlUrlResolverinstanceand assign it authentication credentials by using the NetworkCredentialclass (found in theSystem.Netnamespace) After you define the necessary credentials, you assign the XmlUrlResolverinstance to the XmlTextReaderclass’s XmlResolverproperty so that the secured XML document can

be parsed

LISTING 11.5 Passing Security Credentials to a Remotely Secured XML DocumentDim reader As XmlTextReader = Nothing

Dim xmlUri As String = “http://localhost/XMLChapterVB/Listing1.xml”

‘Get login credentialsDim uid As String = ConfigurationSettings.AppSettings(“UID”)

Trang 2

Dim pwd As String = ConfigurationSettings.AppSettings(“Password”)Dim domain As String = ConfigurationSettings.AppSettings(“Domain”)Dim resolver As New XmlUrlResolver

resolver.Credentials = New NetworkCredential(uid, pwd, domain)Try

reader = New XmlTextReader(xmlUri)

‘Hook resolver to XmlTextReaderreader.XmlResolver = resolverWhile reader.Read() ‘Try to parse documentEnd While

Me.lblOutput.Text = “Parsed secured document.”

Catch exp As ExceptionMe.lblOutput.Text = “Did NOT parse secured document: “ + exp.MessageFinally

If Not (reader Is Nothing) Thenreader.Close()

End IfEnd Try

Version 1.1 of the NET Framework enhances security in the XslTransformclass by markingseveral overloaded versions of the XslTransformclass’s Load()and Transform()methods as obso-lete while adding new, more secure overloaded methods The XslTransformclass’s XmlResolverproperty has also been made obsolete in version 1.1 These changes prohibit XSLT scripts andextension objects, xsl:importand xsl:includestatements, and XSLT document()functions frombeing processed without supplying security evidence and/or an XmlResolverinstance whencalling the Load()and Transform()methods The following sections analyze changes to theXslTransformclass and explain the roles of the XmlResolverandEvidenceclasses

The Load()Method

The XslTransformclass’s Load()method found

in version 1.1 of the NET Framework hasseveral overloads that allow fine-grainedcontrol over whether XSLT scripts, extensionobjects, and xsl:import/xsl:includestate-ments are ignored during an XSLT transfor-mation When local XSLT stylesheets are used

in a transformation, the Load()method stillhas an overload that accepts a String-typeparameter containing the path to thestylesheet Using this overload is the easiestway to transform XML documents via XSLT because it automatically handles included orimported stylesheets as well as compiling embedded script within the stylesheet

LISTING 11.5 Continued

Loading Local XSLT Stylesheets

Using the overloaded Load()method andpassing the physical location of the XSLTstylesheet is fairly straightforward:

Dim xslPath as String = _Server.MapPath(“XSLT/Output.xslt”)Dim trans as New XslTransformtrans.Load(xslPath)

‘Perform transformation

‘with Transform() method

Trang 3

In addition to the overload mentioned previously, there are several new overloads for the Load()method in version 1.1 of the NET Framework The following is one example:

Overloads Public Sub Load( _ByVal stylesheet As IXPathNavigable, _ByVal resolver As XmlResolver, _ByVal evidence As Evidence _)

The IXPathNavigableparameter represents the XSLT stylesheet used in the transformation Thisparameter accepts any object that implements the IXPathNavigableinterface, such as XmlDocument,XPathNavigator, or XPathDocument

The XmlResolverparameter is used to resolve XSLT documents imported into or included in amaster stylesheet When the parameter value is Nothing, imported or included documents areignored When a new XmlUrlResolverinstance is passed into the Load()method, documentsreferenced by xsl:importor xsl:includestatements are resolved and used in the transformation.The XmlUrlResolverclass’s Credentialsproperty can be used in cases where included or importedstylesheets require authentication in order to be accessed (Refer to Listing 11.5 for an example

of using the Credentialsproperty.)The evidenceparameter determines whether XSLT script blocks and extension objects areprocessed based on whether they are from trusted sources The parameter is based on theEvidencetype, located in the System.Security.Policynamespace The NET Framework SDKprovides the following insight into how Evidenceis used:

Security policy is composed of code groups; a particular assembly (the basic unit ofcode for granting security permissions) is a member of a code group if it satisfies thecode group’s membership condition Evidence is the set of inputs to policy thatmembership conditions use to determine to which code groups an assembly belongs.That is, by supplying a proper Evidenceobject to the Load()method, script code containedwithin potentially untrusted XSLT stylesheets can be compiled and used in an XML documenttransformation because the assembly that is generated can be assigned to the proper NETFramework code group If no Evidencetype is supplied, assemblies created during the compila-tion of XSLT script code cannot be used successfully due to their inherit security risks Forexample, when Nothingis passed for the Evidenceparameter, XSLT scripting, extension objects,and document()functions are ignored

In cases where a local XSLT stylesheet has embedded script, uses extension objects, or references

the document()function, the following code can be used to create the proper Evidenceobject forthe assembly:

Me.GetType().Assembly.Evidence

When a remote XSLT stylesheet containing script or extension object references is used in atransformation, the caller of the Load()method must supply evidence in order for script or

Trang 4

extension objects to be executed properly To supply evidence, the XmlSecureResolverclass’sCreateEvidenceForUrl()method can be used The CreateEvidenceForUrl()method accepts a singleString-type parameter that contains the URL for which to create evidence, as shown here:

Dim uri as String = “some uri”

Dim xslDoc as new XPathDocument(uri)

‘Create EvidenceDim e as Evidence = _XmlSecureResolver.CreateEvidenceForUrl(uri)Dim trans as new XslTransform

trans.Load(xslDoc,new XmlUrlResolver(),e)

‘XSLT script, extension objects, etc can be used

‘since evidence was supplied

The Transform()Method

In addition to new overloaded Load()methods, the Transform()method has several new loads that expect an instance of an XmlResolverto be passed as a parameter The following is anexample of one of these overloads:

over-public void Transform(XPathNavigator, XsltArgumentList, _TextWriter, XmlResolver);

In cases where simple XSLT transformations (that is, transformations that involve a single XMLdocument and a single XSLT stylesheet stored locally) are performed, Nothing(nullin C#) can bepassed for the XmlResolverparameter:

Dim writer as new StringWriterDim xsl As New XslTransformxsl.Load(xslPath)

xsl.Transform(doc, Nothing, writer, Nothing)

Passing Nothingfor the XmlResolverparameter when more than one XML document is involved

in the transformation presents a problem For example, when the document()function is usedwithin the XSLT stylesheet to transform multiple XML documents simultaneously, passingNothingcauses any additional XML documents to be ignored In order to perform this type oftransformation successfully, a new XmlUrlResolverinstance must be passed to the Transform()method Listing 11.6 shows how this is done and highlights how evidence can be passed to theLoad() method in cases where a local XSLT stylesheet is used

LISTING 11.6 Using the XslTransformClass’s Load()and Transform()MethodsDim sw As New StringWriter

‘Load XML Doc and master XSLT StylesheetDim xmlDoc As New XPathDocument(Server.MapPath(“XML/Form.xml”))Dim xslDoc As New XPathDocument(Server.MapPath(“XSLT/Form.xslt”))

Trang 5

‘Create XslTransform and load stylesheetDim trans1 As New XslTransform

Dim resolver As New XmlUrlResolvertrans1.Load(xslDoc, resolver, Me.GetType().Assembly.Evidence)

‘Transform XMLtrans1.Transform(xmlDoc, Nothing, sw, resolver)Response.Write(sw.ToString())

sw.Close()

Searching, Filtering, and Sorting XML Data

A little over a year after the XML 1.0 specification was released by the World Wide WebConsortium (W3C), the XPath language emerged on the scene to fill a void created by theinability to effectively search and filter XML data Since its release, XPath has become increas-ingly important in the world of XML and is used in DOM APIs, XSLT stylesheets, XSD schemas,and other XML-specific languages

XPath is a path-based language (it resembles DOS paths in some regards) that allows specializedstatements capable of searching and filtering nodes to be executed against XML documents Thischapter does not provide a complete explanation of the XPath language; for more details on the

XPath language, see the book XML for ASP.NET Developers from Sams Publishing The following

is a sample XPath statement that uses axes, node tests, and a predicate:

/customers/customer[@id=’ALFKI’]

This XPath statement uses the ChildandAttributeaxes, along with node tests and apredicate (the text within the square brackets)

to search for an element named customerthathas an idattribute value equal to ALFKI.When the statement is executed, unwantednodes are automatically filtered out, and thedesired node is returned (assuming that it isfound) Although quite simple, this XPathstatement demonstrates the power of search-ing and filtering data located in an XMLdocument The following sections show how different NET Framework classes can be usedalong with XPath to search, filter, and sort data

Searching and Filtering XML Data

The NET Framework contains several classes that are capable of searching and filtering XMLdata using the XPath language Each class has unique pros and cons, as outlined earlier in this

LISTING 11.6 Continued

Using ADO.NET to Search, Filter, and Sort XML Data

You can also search, filter, and sort XML data

by using the DataSetclass and its relatedclasses After loading XML data into aDataSetinstance by using the ReadXml()method, you can use properties and methods

of the DataTableand DataViewclasses toaccomplish tasks similar to those that theXPath language handles

Trang 6

chapter, and offers different levels of efficiency The XPathNavigatorclass is designed to workhand-in-hand with the XPath language to provide a read-only cursor-style model for navigatingXML nodes Other classes, such as XmlDocumentand XmlNode, provide XPath support through theirSelectNodes()and SelectSingleNode()methods.

When designing applications that consume XML data, you should first look to theXPathNavigatorclass (located in the System.Xml.XPathnamespace) when you need to search XMLdata Although XPathNavigatorisn’t as fast as the forward-only API provided by the XmlTextReaderclass and doesn’t provide the editing capabilities found in the DOM API (this will change inversion 2.0 of the NET Framework when classes such as XPathEditorare introduced), it can beuseful in applications that need the ability to traverse an XML document’s hierarchy along avariety of axes The XPathNavigatorclass offers numerous benefits, such as compiled XPath state-ments and the ability to leverage the IXPathNavigableinterface to search non-XML data stores

The XPathNavigatorclass is abstract, so it can’t be created directly However, you can use classesthat implement the IXPathNavigableinterface (XmlDocument, XmlDataDocument, XmlNode, andXPathDocument) to create a concrete instance of the XPathNavigatorclass by using

CreateNavigator() After the XPathNavigatorinstance is created, you can navigate through theXML document one node at a time When you are positioned on a node, you can reach othernodes located before or after the current node by calling a variety of methods, such asMoveToNext(), MoveToParent(), and MoveToFirstChild()

You can also use XPathNavigatorto search and filter nodes within an XML document by usingXPath statements By leveraging XPath, you can greatly reduce the amount of code that needs

to be written to gather data, thus making applications easier to maintain Nodes returned fromexecuting an XPath statement are placed in an XPathNodeIteratorinstance that can be iteratedthrough easily Before looking at an example of using XPathNavigator’s methods, you shouldexamine the XML document in Listing 11.7, which contains book and author data

LISTING 11.7 An XML Document That Contains Book and Author Data

<?xml version=”1.0”?>

<bookstore>

<book genre=”novel” style=”hardcover”>

<title>The Handmaid’s Tale</title>

<book genre=”novel” style=”hardcover”>

<title>The Worker’s Tale</title>

<author>

<first-name>Margaret</first-name>

<last-name>Atwood</last-name>

</author>

Trang 7

LISTING 11.8 Navigating XML Data by Using XPathNavigatorDim sb as New StringBuilder

Private Sub NavigateBooks()Dim xmlPath As String = Server.MapPath(“Listing7.xml”)

‘Load XML into a non-editable structure

‘This is more efficient than the DOMDim doc As New XPathDocument(xmlPath)

‘Create XPathNavigator by calling CreateNavigator() methodDim nav As XPathNavigator = doc.CreateNavigator()

‘Move to documentnav.MoveToRoot()

‘Move to root element - bookstorenav.MoveToFirstChild()

‘Move to first book child element

Private Sub WalkSiblings(ByVal nav As XPathNavigator)

‘Move to “title” element and get valueDim firstName As String = String.Empty

LISTING 11.7 Continued

Trang 8

Dim lastName As String = String.Emptynav.MoveToFirstChild()

Dim title As String = nav.Valuesb.Append((title + “<br />”))

‘Move back to book elementnav.MoveToParent()

‘access author element under bookDim authorNode As XPathNodeIterator = _nav.SelectChildren(“author”, “”)While authorNode.MoveNext()

‘Move to first-name elementauthorNode.Current.MoveToFirstChild()firstName = authorNode.Current.Value

‘Move to last-name elementauthorNode.Current.MoveToNext()lastName = authorNode.Current.Valuesb.Append((firstName + “ “ + lastName + “<br />”))End While

‘Now move to price elementDim priceNode As XPathNodeIterator = _nav.SelectChildren(“price”, “”)priceNode.MoveNext()

‘Write out value of price elementsb.Append((“$” + priceNode.Current.Value + “<br />”))

‘Search books by author and filter out unwanted booksDim otherBookNodes As XPathNodeIterator = _

nav.Select((“//book[author/first-name=’” + firstName + _

“‘ and author/last-name=’” + lastName + _

“‘ and title != “”” + title + “””]/title”))sb.Append(“<i>Other Books:</i> <br />”)

‘Add other books to output

If otherBookNodes.Count > 0 ThenWhile otherBookNodes.MoveNext()sb.Append((otherBookNodes.Current.Value + “<br />”))End While

Elsesb.Append(“None”)End If

sb.Append(“<p />”)End Sub

LISTING 11.8 Continued

Trang 9

Sorting XML Data

In the past, applications that required XMLdata to be sorted have typically relied onXSLT and the xsl:sortelement due to XPath’s lack of native support for sortingdata Although using XSLT to sort can get the job done, writing stylesheets andtemplates is often overkill and doesn’t workfor all types of data sorts In fact, the XSLT 1.0 specification only supports text and numericsorts “out of the box.”

Fortunately, the reliance on XSLT to sort XML data is minimized in the NET Framework due tonative XML sorting capabilities found in the XPathExpressionand DataViewclasses In addition tobeing able to perform textual and numeric sorts, you can use the XPathExpressionclass toperform custom sorts, using objects that implement the IComparerinterface You can also use theDataViewclass to sort data loaded into a DataTableinstance The following sections demonstratehow to sort XML data by using the XPathNavigatorand XPathExpressionclasses and providedetails on how to leverage the IComparerinterface They also demonstrate how to sort XML data

by using XSD schemas, along with DataTableand DataViewinstances

Sorting with the XPathExpressionClass

You can sort XML nodes by first compiling an XPath statement into an XPathExpressionobject.This is accomplished by calling the XPathNavigatorclass’s Compile()method Then you can add atext or numeric sort to the XPathExpressionobject by calling its AddSort()method AddSort()hastwo overloads:

FIGURE 11.1 Accessing bookand author

nodes by using theXPathNavigatorAPI

Alternatives to XPathNavigator

The XmlDocumentand DataSetclasses couldalso be used to search and filter the XMLdocument shown in Listing 11.7 However,because no editing operations were performed,the XPathDocumentand XPathNavigatorcombination provides a more efficient solution

Trang 10

Overloads Public MustOverride Sub AddSort( _ByVal expr As Object, _

ByVal comparer As IComparer _)

Overloads Public MustOverride Sub AddSort( _ByVal expr As Object, _

ByVal order As XmlSortOrder, _ByVal caseOrder As XmlCaseOrder, _ByVal lang As String, _

ByVal dataType As XmlDataType _)

The first of these overloads allows a custom object implementing IComparerto be used toperform sorts This is useful when more advanced sorts need to take place The second overloadaccepts a sort key, the sort order (ascending or descending), a value indicating how to sortuppercase and lowercase text, a language value, and the type of sort to perform (text ornumeric) Listing 11.9 shows how to use the Compile()and AddSort()methods to sort the newsheadlines shown in Listing 11.1 The code sorts the headlines based on the titleelement, inascending order

LISTING 11.9 Sorting XML Data by Using the XPathNavigatorand XPathExpressionClassesDim sorted As New StringBuilder

‘XPath statementDim xpath As String = “/moreovernews/article/headline_text”

‘Create XPathDocument class so we can get a navigatorDim doc As New XPathDocument(Server.MapPath(“Listing1.xml”))Dim nav As XPathNavigator = doc.CreateNavigator()

‘Compile xpath expressionDim exp As XPathExpression = nav.Compile(xpath)

‘Add a sort based upon the headline_text child text nodeexp.AddSort(“text()”, XmlSortOrder.Ascending, XmlCaseOrder.None, _

“”, XmlDataType.Text)

‘select nodes so we can see the sortDim it As XPathNodeIterator = nav.Select(exp)While it.MoveNext()

‘Grab headline_text valueDim headline As String = it.Current.Value

‘Move to articleit.Current.MoveToParent()

‘Move to urlit.Current.MoveToFirstChild()

Trang 11

‘Grab urlDim url As String = it.Current.Valuesorted.Append(“<tr><td><a href=”””)sorted.Append(url)

sorted.Append(“””>”)sorted.Append(headline)sorted.Append(“</a></td></tr>”)End While

Me.lblNews.Text = sorted.ToString()

Although this type of sorting works well for basic text or numeric sorts, what if you need to sort

a set of nodes based on a Datedata type? Fortunately, one of the AddSort()overloads shownearlier in this section allows a custom object that implements the IComparerinterface to bepassed to it IComparerhas a single method, named Compare(), that you can use to perform avariety of object comparisons Listing 11.10 shows a simple class named DateComparerthatimplements the Compare()method

LISTING 11.10 Creating a Custom Sort Class That Implements IComparerImports System.Collections

Public Class DateComparer : Implements IComparer

Public Function Compare(ByVal date1 As Object, _ByVal date2 As Object) As Integer Implements IComparer.CompareDim intResult As Integer

Dim d1 As DateTime = Convert.ToDateTime(date1)Dim d2 As DateTime = Convert.ToDateTime(date2)intResult = DateTime.Compare(d1, d2)

Return intResult * -1End Function

End Class

The DateComparerclass works by accepting two objects that are converted to DateTimetypes.Upon conversion, the objects are compared to each other, using the DateTimeobject’s Compare()method Compare()returns an integer value from -1to 1, depending on how the dates compare

A value of 0means that the two dates are equal, and a value of -1or 1means that one of thedates is greater than the other (See the NET Framework SDK for more details.) The integercreated by calling DateTime.Compare()is returned from the DateComparerclass’s Compare()methodand used by the XPathExpressionclass to perform the sorting Listing 11.11 shows an example ofusing DateComparerin conjunction with the XPathExpressionclass

LISTING 11.9 Continued

Trang 12

LISTING 11.11 Performing Custom Sorts with the XPathExpressionClassDim sorted As New StringBuilder

Dim xpath As String = “/moreovernews/article/harvest_time”

‘Create XPathDocument class so we can get a navigatorDim doc As New XPathDocument(Server.MapPath(“Listing1.xml”))Dim nav As XPathNavigator = doc.CreateNavigator()

‘Compile xpath expression so we can add a sort to itDim exp As XPathExpression = nav.Compile(xpath)

‘Create IComparer objectDim dc As New DateComparer

‘Pass IComparer object to AddSort()exp.AddSort(“text()”, dc)

‘select nodes so we can see the sortDim it As XPathNodeIterator = nav.Select(exp)While it.MoveNext()

‘Grab harvest_time valueDim [date] As String = it.Current.Value

‘Move to article parentit.Current.MoveToParent()

‘Move to urlit.Current.MoveToFirstChild()

‘Grab urlDim url As String = it.Current.Value

‘Move to headlineit.Current.MoveToParent()Dim headlineIt As XPathNodeIterator = _it.Current.SelectChildren(“headline_text”, String.Empty)headlineIt.MoveNext()

Dim headline As String = headlineIt.Current.Value

sorted.Append(“<tr><td><a href=”””)sorted.Append(url)

sorted.Append(“””>”)sorted.Append(headline)sorted.Append(“</a></td><td>”)sorted.Append([date])

sorted.Append(“</td></tr>”)End While

‘Add data to a PlaceHolder server control named phNews Me.phNews.Controls.Add(New LiteralControl(sorted.ToString()))

Trang 13

Figure 11.2 shows the HTML output generated after running the code shown in Listing 11.11.Notice that the news headlines are properly sorted by date and time.

FIGURE 11.2The result of sorting XML nodesbased on date and time

Sorting with the DataViewClass

You can use ADO.NET’s DataViewclass in combination with the DataSetand DataTableclasses tosort XML data Using the DataViewclass to sort XML is generally attractive to ASP.NET developersbecause they can use it to bind views to a variety of ASP.NET controls, including the DataGridcontrol When you set it up properly, you can even use the DataViewclass to sort dates foundwithin XML data, without resorting to using a custom class that implements the IComparerinter-face discussed earlier

To sort by using the DataViewclass, you must first load the XML data into a DataSetinstance bycalling the ReadXml()method You can then create a DataViewobject based on the appropriateDataTablewithin the DataSetinstance To sort based on a specific column, you assign theDataColumnname to the DataViewobject’s Sortproperty You can then assign the DataViewobject

to the DataSourceproperty of a variety of ASP.NET Web controls

Following these steps works well for text-based sorts, but what happens if you want to sortnumerically or by date? To sort based on dates contained within an XML document, the columnrepresenting the date data must be defined as a DateTimetype within the DataTableobject.Although you can do this programmatically, a more flexible solution is to preload an XSDschema that describes the XML document structure and its types into the DataSetobject TheXSD schema can be loaded by calling the DataSetobject’sReadXmlSchema()method When youload the schema into the DataSetinstance, all the DataColumninstances will be properly typed sothat sorting can occur on different types (such as DateTime) by using the DataViewobject

Before showing the code to sort XML data by date using a DataViewinstance, we need tomention a gotcha XSD schema date types format dates differently than do Common Language

Trang 14

Runtime (CLR) DateTimetypes For example, you can load the harvest_timeelement shown inListing 11.1 into a DateTimestructure by using its Parse()method:

Dim date as DateTime = DateTime.Parse(“Jan 14 2004 8:57PM”)

However, this date is not valid, according to the XSD schema specification As a result, it willcause an error when it is loaded into a DataSetinstance that has been preloaded with an XSDschema defining the harvest_timeelement as a Datedata type To make the data conform to theDatedata type defined in the schema specification, you need to change it to the followingformat:

2004-01-14T20:57:00.0000000-07:00

Although you could potentially do this conversion by hand, the XmlConvertclass can handle itwith a single line of code (see Listing 11.12) Failure to properly perform this conversion willresult in an error when the XML is loaded into the DataSetinstance:

String was not recognized as a valid DateTime

Although this gotcha causes a minor inconvenience when you’re trying to sort the news data inListing 11.1 by harvest_time, you can easily overcome it by using the XmlDocumentand XmlConvertclasses to manipulate the date values The code in Listing 11.12 shows how to use these classes

as well as perform several other tasks, including the following:

n Loading the news XML data into the DOM

n Converting all harvest_timetext node values to valid schema Datedata types by using theXmlConvertclass’s ToString()method

n Serializing the DOM structure to a MemoryStreamobject

n Loading the MemoryStreamobject into a DataSetinstance that is preloaded with an XSDschema to properly type the different DataTablecolumns

n Creating a DataViewobject based on the DataSetobject’s first DataTable

n Identifying a sort column by using the DataViewobject’s Sortproperty

n Binding the DataViewto an ASP.NET DataGridserver control

LISTING 11.12 Sorting XML Data by Using the DataViewClass

‘Fix Listing1.xml dates to be schema “compatible” using DOMDim doc As New XmlDocument

doc.Load(Server.MapPath(“Listing1.xml”))

‘Find all harvest_time nodesDim dateNodes As XmlNodeList = doc.SelectNodes(“//harvest_time”)For Each dateNode as XmlNode In dateNodes

Dim newDate As DateTime = DateTime.Parse(dateNode.InnerText)

‘Convert harvest_time string to XSD Schema data type string

Trang 15

dateNode.InnerText = XmlConvert.ToString(newDate)Next dateNode

‘Save updated harvest_time XML to a StreamDim ms As New MemoryStream

doc.Save(ms)ms.Position = 0

Dim ds As New DataSet

‘Load schemads.ReadXmlSchema(Server.MapPath(“Listing12.xsd”))

‘Load XML data into DataSetds.ReadXml(ms)

‘Create DataViewDim view As DataView = ds.Tables(0).DefaultView

‘Sort on date columnview.Sort = “harvest_time DESC”

Me.dgNews.DataSource = viewMe.dgNews.DataBind()ms.Close()

Figure 11.3 shows the result of sorting the XML headlines based on harvest_time.LISTING 11.12 Continued

FIGURE 11.3The result of sorting XML nodesbased on date and time with aDataViewinstance

Searching Namespace Qualified Nodes

The NET Framework prevents naming collisions by logically organizing classes into namespaces.XML documents also prevent naming collisions by using namespaces, although the way they

Trang 16

are defined is quite different Namespace qualified nodes are logically separated from othernodes (think of XML nodes as being organized into different rooms in a building based on theirnamespace URIs) to make them easy to locate and to avoid collisions Two different types ofXML namespaces exist: default and local

The following is an example of defining a default namespace:

Public Overridable Sub AddNamespace( _ByVal prefix As String, _

ByVal uri As String _)

Although XmlNamespaceManageris often used when namespaces need to be dynamically addedinto XML fragments, it can also be used when executing XPath statements To query articlenodes located in a default namespace (such as the one shown earlier in this section), you can add the default namespace to the XmlNamespaceManagerinstance and then use it in the XPath statement The code shown in Listing 11.13 illustrates this process Adding theXmlNamespaceManagernamespace data into the context of the XPath statement is accomplished

by using the XPathExpressionclass’s SetContext()method

Trang 17

LISTING 11.13 Searching for Nodes in a Default Namespace by Using XpathNavigatorDim xmlPath As String = Server.MapPath(“Listing13.xml”)

‘Load XMLDim doc As New XPathDocument(xmlPath)

‘Create navigatorDim nav As XPathNavigator = doc.CreateNavigator()Dim ns As New XmlNamespaceManager(nav.NameTable)

‘Define default namespace Prefix can be any valid XML namespace

‘prefix valuens.AddNamespace(“ns”, “http://www.moreover.com”)

‘Add default prefix into xpath statement to account for

‘default namespaceDim xpath As String = “/ns:moreovernews/ns:article/” + “ns:headline_text”

‘Create a compiled xpath statement and set context to include

‘the namespace manager data

Dim exp As XPathExpression = nav.Compile(xpath)exp.SetContext(ns)

‘Select nodes and write out the headlinesDim it As XPathNodeIterator = nav.Select(exp)While it.MoveNext()

‘Create navigatorDim nav As XPathNavigator = doc.CreateNavigator()Dim ns As New XmlNamespaceManager(nav.NameTable)

‘Define news namespace prefix and URK

ns.AddNamespace(“news”, “http://www.moreover.com”)

‘Add news prefix into xpath statementDim xpathNS As String = “/moreovernews/news:article/headline_text”

‘Create a compiled xpath statement and set context to include

‘the namespace manager data

Trang 18

Dim exp As XPathExpression = nav.Compile(xpathNS)exp.SetContext(ns)

‘Select nodes and write out the headlinesDim it As XPathNodeIterator = nav.Select(exp)While it.MoveNext()

Me.lblNoNamespace.Text += it2.Current.Value + “<br />”

End While

You can also use the XmlNamespaceManagerobject to search for namespace qualified nodes, usingthe XmlDocumentclass, as shown in Listing 11.15 The XmlDocumentclass’s SelectNodes()method(which is inherited from XmlNode) contains an overload that accepts an XmlNamespaceManagerobject as a parameter

LISTING 11.15 Searching for Nodes in a Local Namespace by Using XmlDocumentDim xmlPath As String = Server.MapPath(“Listing14.xml”)

Dim doc As New XmlDocumentdoc.Load(xmlPath)

Dim ns As New XmlNamespaceManager(doc.NameTable)ns.AddNamespace(“news”, “http://www.moreover.com”)Dim xpathLocal As String = “/moreovernews/news:article/headline_text”

Dim newsNodes As XmlNodeList = doc.SelectNodes(xpathLocal, ns)For Each newsNode As XmlNode In newsNodes

Trang 19

Creating a Reusable XML Validation Class

In addition to creating Web form front-end code, ASP.NET programmers are often charged withdeveloping a variety of back-end processes, such as those that access remote XML data and store

it in a database for later retrieval These types of processes may involve validating the XML data

to ensure that it is structured properly and contains valid data types that properly match upwith database fields By validating XML data first, you can catch potential errors ahead of time,before any SQL statements are executed in the database

The NET Framework supports validating XML documents using several different types of ments including DTDs, XML Data-Reduced (XDR) schemas, and XSD schemas XSD schemasoffer the most power and flexibility of the three choices, through their support for validating adocument’s structure as well as the data types it contains You can find more information aboutXSD schemas at the W3C Web site: www.w3.org

docu-XML documents can be programmatically validated by using the XmlValidatingReaderclasslocated in the NET Framework’s System.Xmlnamespace You can use this class to validate docu-ments against DTD, XDR, or XSD schema documents Like the XmlTextReaderclass, it provides afast, forward-only API that can handle large XML documents quickly and efficiently

XmlValidatingReaderexposes a ValidationHandlerevent that is called when the validation processerrors, such as when incorrect element nesting or invalid data types are encountered

Although you can write validation code from scratch each time you need to validate an XMLdocument, encapsulating validation code into a wrapper class brings many object-orientedcoding benefits, including encapsulation and code reuse If you write a wrapper class, developerswith different skill levels can perform XML document validation more easily; also, validationcode can be simplified when multiple applications share the same code base

Listing 11.16 contains the skeleton for a reusable XML validation component that uses theXmlValidatingReaderclass The XmlValidatorclass relies on a helper structure named

XmlValidationStatusto report if XML documents are valid to calling applications

LISTING 11.16 A Skeleton for a Reusable XML Validator Class and Helper StructurePublic Class XmlValidator

Public Function Validate(ByVal xml As Object, _ByVal schemaCol As XmlSchemaCollection, _ ByVal dtdInfo() As String, ByVal logError As Boolean, _ ByVal logFile As String) As XmlValidationStatus End Function

Private Sub ValidationCallBack(ByVal sender As Object, _ ByVal args As ValidationEventArgs)

End Sub

Trang 20

The logErrorand logFileparameters are self-explanatory, but the others need further tion The xmlparameter is typed as Objectto allow different types of XML data sources to bevalidated Valid XML data source types include StringReader, String, and Stream Passing anyother types for the xmlparameter value will cause an ApplicationExceptionerror to be thrown.

explana-The schemaColparameter accepts an XmlSchemaCollectioninstance (XmlSchemaCollectionis located

in the System.Xml.Schemanamespace) that contains one or more schemas used to validate theXML data source When DTDs are used for validation, the DTD DocTypeName(the root element ofthe XML document) is passed as the first item in the Stringarray, followed by the physical path

to the DTD document Listing 11.17 shows the complete code for the Validate()method

LISTING 11.17 The Validate()and ValidationCallBack()MethodsPrivate _valid As Boolean

Private _logError As BooleanPrivate _logFile As StringPrivate _validationErrors As String = String.EmptyPrivate xmlReader As XmlTextReader = NothingPrivate vReader As XmlValidatingReader = Nothing

Public Function Validate(ByVal xml As Object, _ByVal schemaCol As XmlSchemaCollection, _ByVal dtdInfo() As String, ByVal logError As Boolean, _ByVal logFile As String) As XmlValidationStatus

_logError = logError_logFile = logFile_valid = True

Try

‘Check what type of XML data source was passed

If TypeOf xml Is StringReader ThenxmlReader = New XmlTextReader(CType(xml, StringReader))ElseIf TypeOf xml Is String Then

xmlReader = New XmlTextReader(CType(xml, String))

LISTING 11.16 Continued

Trang 21

ElseIf TypeOf xml Is Stream ThenxmlReader = New XmlTextReader(CType(xml, Stream))Else

Throw New ApplicationException(“Invalid XML data “ + _

“source passed.”)End If

‘Hookup DTD or Schemas

If Not (dtdInfo Is Nothing) Then

If dtdInfo.Length > 0 ThenDim context As New XmlParserContext(Nothing, Nothing, _dtdInfo(0), “”, dtdInfo(1), “”, dtdInfo(1), “”, _XmlSpace.Default)

xmlReader.MoveToContent()vReader = _

New XmlValidatingReader(xmlReader.ReadOuterXml(), _XmlNodeType.Element, context)

vReader.ValidationType = ValidationType.DTDEnd If

ElsevReader = New XmlValidatingReader(xmlReader)vReader.ValidationType = ValidationType.Auto

If Not (schemaCol Is Nothing) ThenvReader.Schemas.Add(schemaCol)End If

End If

‘Associate validating reader with callback method

‘to handle any validation errorsAddHandler vReader.ValidationEventHandler, _AddressOf Me.ValidationCallBack

‘ Parse through XML documentWhile vReader.Read()

End WhileCatch_valid = FalseFinally ‘Close validating reader

If Not (vReader Is Nothing) ThenvReader.Close()

End IfEnd Try

‘Report back to calling application

LISTING 11.17 Continued

Trang 22

Dim status As New XmlValidationStatusstatus.Status = _valid

status.ErrorMessages = _validationErrorsReturn status

writer.WriteLine()writer.WriteLine((args.Message + “ “ + today.ToString()))writer.WriteLine()

If xmlReader.LineNumber > 0 Thenwriter.WriteLine((“Line: “ + xmlReader.LineNumber + _

“ Position: “ + xmlReader.LinePosition))End If

writer.WriteLine()writer.Flush()Else ‘Track error messages_validationErrors = args.Message + “ Line: “ + _xmlReader.LineNumber.ToString() + _

“ Column:” + xmlReader.LinePosition.ToString() + _ControlChars.Lf + ControlChars.Lf

End IfCatchFinally ‘Ensure StreamWriter gets closed

If Not (writer Is Nothing) Thenwriter.Close()

End IfEnd TryEnd Sub

Validate()starts by loading the XML data source into an XmlTextReaderinstance, hooking

up schemas or DTDs, and then instantiating the XmlValidatingReaderinstance Any errorsLISTING 11.17 Continued

Trang 23

encountered during the XML validationprocess cause the ValidationCallBackmethod

to be called; this method handles trackingand logging errors Upon completion, the Validate()method creates anXmlValidationStatusstructure and assignsappropriate values to its fields

Listing 11.18 provides an example of puttingthe XmlValidatorclass to use Any errorsfound during the validation operation arewritten back to the page in this example, butthey could instead be logged to a file

LISTING 11.18 Using the XmlValidatorClass to Validate XML Data

‘Define logging folder to use when logging is turned onDim logFile As String = Server.MapPath(“Log.txt”)Dim xmlFilePath As String = Server.MapPath(“Listing18.xml”)

‘Create schema collection object and add schema to itDim schemaCol As New XmlSchemaCollection

If valStatus.Status = True ThenMe.lblOutput.Text = “<b>Validation was SUCCESSFUL!</b>”

‘Call method to process XML document for backend processElse

Me.lblOutput.Text = “<b>Validation failed!</b><p />”

Me.lblOutput.Text += valStatus.ErrorMessagesEnd If

Converting Relational Data to XML

Web applications have come a long way since the early days of the Internet Many of the firstapplications relied on data stored in local databases or flat files and provided little to no flexibil-ity for accessing data from distributed sources As the Internet has evolved, more advanced dataaccess technologies have come about that allow data from a variety of locations and sources to

be used in Web applications This has resulted in companies automating business processes andultimately cutting operational costs

Other Uses for the XmlValidator Class

Although the example in Listing 11.18 usesthe XmlValidatorclass from within anASP.NET page, a more realistic and usefulapproach might be to have a Windowsservice that automatically grabs XML docu-ments from a variety of locations and vali-dates them Valid XML documents could then

be moved into a database or stored on thefile system for later retrieval You can find anexample of creating a Windows service forthis purpose at www.xmlforasp.net/

codeSection.aspx?csID=77

Trang 24

ADO.NET represents one of the most powerful technologies to have evolved out of the old nologies of the Internet When you use ADO.NET, only a few lines of code are required to loaddata from a relational database and convert it to XML for transport between different businessentities, binding to hierarchical controls, transformation with XSLT, and many other purposes.

tech-The following sections provide several pure NET Framework techniques for converting tional data to XML and show how you can customize the structure of an XML document

rela-Customizing XML by Using the DataSet Class

The DataSetclass exposes two methods named GetXml()and WriteXml()that can be used to easilyconvert relational data into XML GetXml()returns a string that contains the XML data, andWriteXml()can write XML data to a file or to a TextWriter, Stream, or XmlWriterinstance Bothmethods generate XML documents that are element-centric The root node of the generatedXML is named after the DataSetinstance, and each child of the root is named based onDataTableinstances in the DataSetinstance

Although the default XML structure generated by the DataSetinstance might be fine for someapplications, others might require the structure to be customized so that the data can be inte-grated into another application or matched up with a schema You can customize the XMLstructure by using the DataColumnand DataRelationclasses You can use theDataColumnclass tocontrol whether data is mapped to elements or attributes, and you can use the DataRelationclass

Attribute Data is mapped to an attribute

Hidden Data is not output in the generated XML

SimpleContent Data is mapped to an XmlTextnode

Changing the MappingTypevalue allows you to shape the XML data as desired Listing 11.19demonstrates how to load data from the Northwind database’s Customerstable into a DataSetinstance and use the ColumnMappingproperty of the DataColumnclass to associate primary key datawith an attribute

LISTING 11.19 Shaping XML Data by Using the ColumnMappingPropertyDim connStr As String = ConfigurationSettings.AppSettings(“ConnStr”)Dim sql As String = “SELECT * FROM Customers “ + _

“WHERE CustomerID = ‘ALFKI’”

Dim conn As New SqlConnection(connStr)

Trang 25

Dim da As New SqlDataAdapter(sql, conn)

‘Provide root name for XML documentDim ds As New DataSet(“Customers”)

‘Provide name for each child element of rootda.Fill(ds, “Customer”)

‘Map CustomerID field to an attributeds.Tables(0).Columns(“CustomerID”).ColumnMapping = _MappingType.Attribute

Me.txtXml.Text = ds.GetXml()conn.Close()

The following XML is generated after running the code in Listing 11.19 (notice that the ment’s root node is named after the DataSetinstance and that the CustomerIDdata is defined as

LISTING 11.20 Nesting XML Based on Primary/Foreign-Key RelationshipsDim connStr As String = ConfigurationSettings.AppSettings(“ConnStr”)Dim sql As String = “SELECT * FROM “ + _

“Customers WHERE CustomerID = ‘ALFKI’;”

sql += “SELECT * FROM Orders WHERE CustomerID = ‘ALFKI’”

LISTING 11.19 Continued

Ngày đăng: 21/01/2014, 09:20

TỪ KHÓA LIÊN QUAN

w