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

Apress pro LINQ Language Integrated Query in C# 2008 phần 7 pptx

52 320 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

Định dạng
Số trang 52
Dung lượng 842,15 KB

Nội dung

CHAPTER 9 ■ ADDITIONAL XML CAPABILITIES 327 try { xDocument.Validate(schemaSet, (o, vea) => { Console.WriteLine( "A validation error occurred processing object type {0}.", o.GetType().Name); Console.WriteLine(vea.Message); throw (new Exception(vea.Message)); }); Console.WriteLine("Document validated successfully."); } catch (Exception ex) { Console.WriteLine("Exception occurred: {0}", ex.Message); Console.WriteLine("Document validated unsuccessfully."); } Check that out. An entire method specified as a lambda expression. Do lambda expressions rock or what? Here are the results: Here is the source XML document: <BookParticipants> <BookParticipant type="Author" language="English"> <FirstName>Joe</FirstName> <LastName>Rattz</LastName> </BookParticipant> <BookParticipant type="Editor"> <FirstName>Ewan</FirstName> <LastName>Buckingham</LastName> </BookParticipant> </BookParticipants> A validation error occurred processing object type XAttribute. The 'language' attribute is not declared. Exception occurred: The 'language' attribute is not declared. Document validated unsuccessfully. Now, I’ll try an example specifying to add the schema information, as shown in Listing 9-17. Listing 9-17. Unsuccessfully Validating an XML Document Against an XSD Schema Using a Lambda Expression and Specifying to Add Schema Information XDocument xDocument = new XDocument( new XElement("BookParticipants", new XElement("BookParticipant", new XAttribute("type", "Author"), new XElement("FirstName", "Joe"), new XElement("MiddleName", "Carson"), new XElement("LastName", "Rattz")), Rattz_789-3.book Page 327 Tuesday, October 16, 2007 2:21 PM 328 CHAPTER 9 ■ ADDITIONAL XML CAPABILITIES new XElement("BookParticipant", new XAttribute("type", "Editor"), new XElement("FirstName", "Ewan"), new XElement("LastName", "Buckingham")))); Console.WriteLine("Here is the source XML document:"); Console.WriteLine("{0}{1}{1}", xDocument, System.Environment.NewLine); XmlSchemaSet schemaSet = new XmlSchemaSet(); schemaSet.Add(null, "bookparticipants.xsd"); xDocument.Validate(schemaSet, (o, vea) => { Console.WriteLine("An exception occurred processing object type {0}.", o.GetType().Name); Console.WriteLine("{0}{1}", vea.Message, System.Environment.NewLine); }, true); foreach(XElement element in xDocument.Descendants()) { Console.WriteLine("Element {0} is {1}", element.Name, element.GetSchemaInfo().Validity); XmlSchemaElement se = element.GetSchemaInfo().SchemaElement; if (se != null) { Console.WriteLine( "Schema element {0} must have MinOccurs = {1} and MaxOccurs = {2}{3}", se.Name, se.MinOccurs, se.MaxOccurs, System.Environment.NewLine); } else { // Invalid elements will not have a SchemaElement. Console.WriteLine(); } } This example starts like the previous. It creates an XML document. This time, though, I added an additional element for the first BookParticipant: MiddleName. This is invalid because it is not spec- ified in the schema I am validating against. Unlike the previous example, I specify for the Validate method to add the schema information. Also, unlike the previous example, I am not throwing an exception in my validation event handling code. As you may recall, I mentioned previously that the validation must complete to have the schema information added, so your handler must not throw an exception. Therefore, I also removed the try/catch block as well. After the validation completes, I am enumerating all the elements in the document and displaying whether they are valid. Additionally, I obtain the SchemaElement object from the added schema infor- mation. Notice that I make sure the SchemaElement property is not null, because if the element is not valid, the SchemaElement property may be null. After all, the element may not be valid because it is not in the schema, so how could there be schema information? The same applies to the SchemaAttribute property for invalid attributes. Once I have a SchemaElement object, I display its Name, MinOccurs, and MaxOccurs properties. Rattz_789-3.book Page 328 Tuesday, October 16, 2007 2:21 PM CHAPTER 9 ■ ADDITIONAL XML CAPABILITIES 329 Here are the results: Here is the source XML document: <BookParticipants> <BookParticipant type="Author"> <FirstName>Joe</FirstName> <MiddleName>Carson</MiddleName> <LastName>Rattz</LastName> </BookParticipant> <BookParticipant type="Editor"> <FirstName>Ewan</FirstName> <LastName>Buckingham</LastName> </BookParticipant> </BookParticipants> An exception occurred processing object type XElement. The element 'BookParticipant' has invalid child element 'MiddleName'. List of possible elements expected: 'LastName'. Element BookParticipants is Invalid Schema element BookParticipants must have MinOccurs = 1 and MaxOccurs = 1 Element BookParticipant is Invalid Schema element BookParticipant must have MinOccurs = 1 and MaxOccurs = 79228162514264337593543950335 Element FirstName is Valid Schema element FirstName must have MinOccurs = 1 and MaxOccurs = 1 Element MiddleName is Invalid Element LastName is NotKnown Element BookParticipant is Valid Schema element BookParticipant must have MinOccurs = 1 and MaxOccurs = 79228162514264337593543950335 Element FirstName is Valid Schema element FirstName must have MinOccurs = 1 and MaxOccurs = 1 Element LastName is Valid Schema element LastName must have MinOccurs = 1 and MaxOccurs = 1 There are no real surprises in this output. Notice that the MaxOccurs property value for the BookParticipant element is a very large number. This is because in the schema, the maxOccurs attribute is specified to be "unbounded". For the final pair of validation examples, I will use one of the Validate method prototypes that applies to validating elements. The first thing you will notice about it is that it has an argument that requires an XmlSchemaObject to be passed. This means the document must have already been validated. This seems odd. This is for a scenario where we have already validated once and need to revalidate a portion of the XML tree. For this scenario, imagine I load an XML document and validate it to start. Next, I have allowed a user to update the data for one of the book participants and now need to update the XML document Rattz_789-3.book Page 329 Tuesday, October 16, 2007 2:21 PM 330 CHAPTER 9 ■ ADDITIONAL XML CAPABILITIES to reflect the user’s changes, and I want to validate that portion of the XML tree again, after the updates. This is where the Validate method prototypes of the elements and attributes can come in handy. Because this example, shown in Listing 9-18, is more complex than some of the previous exam- ples, I will explain it as I go. First, to be a little different, and because I need an expanded schema to facilitate an edit to the XML tree, I will define the schema programmatically instead of loading it from a file, as I have in the previous examples. Listing 9-18. Successfully Validating an XML Element string schema = @"<?xml version='1.0' encoding='utf-8'?> <xs:schema attributeFormDefault='unqualified' elementFormDefault='qualified' xmlns:xs='http://www.w3.org/2001/XMLSchema'> <xs:element name='BookParticipants'> <xs:complexType> <xs:sequence> <xs:element maxOccurs='unbounded' name='BookParticipant'> <xs:complexType> <xs:sequence> <xs:element name='FirstName' type='xs:string' /> <xs:element minOccurs='0' name='MiddleInitial' type='xs:string' /> <xs:element name='LastName' type='xs:string' /> </xs:sequence> <xs:attribute name='type' type='xs:string' use='required' /> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>"; XmlSchemaSet schemaSet = new XmlSchemaSet(); schemaSet.Add("", XmlReader.Create(new StringReader(schema))); In the previous code, I merely copied the schema from the file that I have been using. I did a search on the double quotes and replaced them with single quotes. I also added a MiddleInitial element between the FirstName and LastName elements. Notice that I specify the minOccurs attribute as 0 so the element is not required. Next, I create a schema set from the schema. Next, it’s time to create an XML document: XDocument xDocument = new XDocument( new XElement("BookParticipants", new XElement("BookParticipant", new XAttribute("type", "Author"), new XElement("FirstName", "Joe"), new XElement("LastName", "Rattz")), new XElement("BookParticipant", new XAttribute("type", "Editor"), new XElement("FirstName", "Ewan"), new XElement("LastName", "Buckingham")))); Console.WriteLine("Here is the source XML document:"); Console.WriteLine("{0}{1}{1}", xDocument, System.Environment.NewLine); Rattz_789-3.book Page 330 Tuesday, October 16, 2007 2:21 PM CHAPTER 9 ■ ADDITIONAL XML CAPABILITIES 331 There is nothing new here. I just created the same document I usually do for the examples and displayed it. Now I will validate the document: bool valid = true; xDocument.Validate(schemaSet, (o, vea) => { Console.WriteLine("An exception occurred processing object type {0}.", o.GetType().Name); Console.WriteLine(vea.Message); valid = false; }, true); Console.WriteLine("Document validated {0}.{1}", valid ? "successfully" : "unsuccessfully", System.Environment.NewLine); Notice that I validate a little differently than I have in previous examples. I initialize a bool to true, representing whether the document is valid. Inside the validation handler, I set it to false. So if a validation error occurs, valid will be set to false. I then check the value of valid after validation to determine whether the document is valid, and display its validity. In this example, the document is valid at this point. Now, it’s time to imagine that I am allowing a user to edit any particular book participant. The user has edited the book participant whose first name is "Joe". So I obtain a reference for that element, update it, and revalidate it after the update: XElement bookParticipant = xDocument.Descendants("BookParticipant"). Where(e => ((string)e.Element("FirstName")).Equals("Joe")).First(); bookParticipant.Element("FirstName"). AddAfterSelf(new XElement("MiddleInitial", "C")); valid = true; bookParticipant.Validate(bookParticipant.GetSchemaInfo().SchemaElement, schemaSet, (o, vea) => { Console.WriteLine("An exception occurred processing object type {0}.", o.GetType().Name); Console.WriteLine(vea.Message); valid = false; }, true); Console.WriteLine("Element validated {0}.{1}", valid ? "successfully" : "unsuccessfully", System.Environment.NewLine); As you can see, I initialize valid to true and call the Validate method, this time on the bookParticipant element instead of the entire document. Inside the validation event handler, I set valid to false. After validation of the book participant element, I display its validity. Here are the results: Rattz_789-3.book Page 331 Tuesday, October 16, 2007 2:21 PM 332 CHAPTER 9 ■ ADDITIONAL XML CAPABILITIES Here is the source XML document: <BookParticipants> <BookParticipant type="Author"> <FirstName>Joe</FirstName> <LastName>Rattz</LastName> </BookParticipant> <BookParticipant type="Editor"> <FirstName>Ewan</FirstName> <LastName>Buckingham</LastName> </BookParticipant> </BookParticipants> Document validated successfully. Element validated successfully. As you can see, the validation of the element is successful. For the final example, I have the same code, except this time when I update the BookParticipant element, I will create a MiddleName element, as opposed to MiddleInitial, which is not valid. Listing 9-19 is the code. Listing 9-19. Unsuccessfully Validating an XML Element string schema = @"<?xml version='1.0' encoding='utf-8'?> <xs:schema attributeFormDefault='unqualified' elementFormDefault='qualified' xmlns:xs='http://www.w3.org/2001/XMLSchema'> <xs:element name='BookParticipants'> <xs:complexType> <xs:sequence> <xs:element maxOccurs='unbounded' name='BookParticipant'> <xs:complexType> <xs:sequence> <xs:element name='FirstName' type='xs:string' /> <xs:element minOccurs='0' name='MiddleInitial' type='xs:string' /> <xs:element name='LastName' type='xs:string' /> </xs:sequence> <xs:attribute name='type' type='xs:string' use='required' /> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>"; XmlSchemaSet schemaSet = new XmlSchemaSet(); schemaSet.Add("", XmlReader.Create(new StringReader(schema))); Rattz_789-3.book Page 332 Tuesday, October 16, 2007 2:21 PM CHAPTER 9 ■ ADDITIONAL XML CAPABILITIES 333 XDocument xDocument = new XDocument( new XElement("BookParticipants", new XElement("BookParticipant", new XAttribute("type", "Author"), new XElement("FirstName", "Joe"), new XElement("LastName", "Rattz")), new XElement("BookParticipant", new XAttribute("type", "Editor"), new XElement("FirstName", "Ewan"), new XElement("LastName", "Buckingham")))); Console.WriteLine("Here is the source XML document:"); Console.WriteLine("{0}{1}{1}", xDocument, System.Environment.NewLine); bool valid = true; xDocument.Validate(schemaSet, (o, vea) => { Console.WriteLine("An exception occurred processing object type {0}.", o.GetType().Name); Console.WriteLine(vea.Message); valid = false; }, true); Console.WriteLine("Document validated {0}.{1}", valid ? "successfully" : "unsuccessfully", System.Environment.NewLine); XElement bookParticipant = xDocument.Descendants("BookParticipant"). Where(e => ((string)e.Element("FirstName")).Equals("Joe")).First(); bookParticipant.Element("FirstName"). AddAfterSelf(new XElement("MiddleName", "Carson")); valid = true; bookParticipant.Validate(bookParticipant.GetSchemaInfo().SchemaElement, schemaSet, (o, vea) => { Console.WriteLine("An exception occurred processing object type {0}.", o.GetType().Name); Console.WriteLine(vea.Message); valid = false; }, true); Console.WriteLine("Element validated {0}.{1}", valid ? "successfully" : "unsuccessfully", System.Environment.NewLine); Rattz_789-3.book Page 333 Tuesday, October 16, 2007 2:21 PM 334 CHAPTER 9 ■ ADDITIONAL XML CAPABILITIES This code is identical to the previous example except instead of adding a MiddleInitial element, I added a MiddleName element that is invalid. Here are the results: Here is the source XML document: <BookParticipants> <BookParticipant type="Author"> <FirstName>Joe</FirstName> <LastName>Rattz</LastName> </BookParticipant> <BookParticipant type="Editor"> <FirstName>Ewan</FirstName> <LastName>Buckingham</LastName> </BookParticipant> </BookParticipants> Document validated successfully. An exception occurred processing object type XElement. The element 'BookParticipant' has invalid child element 'MiddleName'. List of possible elements expected: 'MiddleInitial, LastName'. Element validated unsuccessfully. As you can see, the element is no longer valid. Now, this example may seem a little hokey because I said to imagine a user is editing the document. No developer in their right mind would create a user interface that would intentionally allow a user to create edits that would be invalid. But imagine if that user is in reality some other process on the XML document. Perhaps you passed the XML docu- ment to someone else’s program to make some update and you know they personally have it in for you and are seeking your personal destruction. Now it may make sense to revalidate. You know you can’t trust them. XPath If you are accustomed to using XPath, you can also gain some XPath query capabilities thanks to the System.Xml.XPath.Extensions class in the System.Xml.XPath namespace. This class adds XPath search capability via extension methods. Prototypes Here is a list of some of the method prototypes available in the System.Xml.XPath.Extensions class: XPathNavigator Extensions.CreateNavigator(this XNode node); XPathNavigator Extensions.CreateNavigator(this XNode node, XmlNameTable nameTable); object Extensions.XPathEvaluate(this XNode node, string expression); object Extensions.XPathEvaluate(this XNode node, string expression, IXmlNamespaceResolver resolver); XElement Extensions.XPathSelectElement(this XNode node, string expression); XElement Extensions.XPathSelectElement(this XNode node, string expression, IXmlNamespaceResolver resolver); Rattz_789-3.book Page 334 Tuesday, October 16, 2007 2:21 PM CHAPTER 9 ■ ADDITIONAL XML CAPABILITIES 335 IEnumerable<XElement> Extensions.XPathSelectElements(this XNode node, string expression); IEnumerable<XElement> Extensions.XPathSelectElements(this XNode node, string expression, IXmlNamespaceResolver resolver); Examples Using these extension methods, it is possible to query a LINQ to XML document using XPath search expressions. Listing 9-20 is an example. Listing 9-20. Querying XML with XPath Syntax XDocument xDocument = new XDocument( new XElement("BookParticipants", new XElement("BookParticipant", new XAttribute("type", "Author"), new XElement("FirstName", "Joe"), new XElement("LastName", "Rattz")), new XElement("BookParticipant", new XAttribute("type", "Editor"), new XElement("FirstName", "Ewan"), new XElement("LastName", "Buckingham")))); XElement bookParticipant = xDocument.XPathSelectElement( "//BookParticipants/BookParticipant[FirstName='Joe']"); Console.WriteLine(bookParticipant); As you can see, I created my typical XML document. I didn’t display the document this time, though. I called the XPathSelectElement method on the document and provided an XPath search expression to find the BookParticipant element whose FirstName element’s value is "Joe". Here are the results: <BookParticipant type="Author"> <FirstName>Joe</FirstName> <LastName>Rattz</LastName> </BookParticipant> Using the XPath extension methods, you can obtain a reference to a System.Xml.XPath. XPathNavigator object to navigate your XML document, perform an XPath query to return an element or sequence of elements, or evaluate an XPath query expression. Summary At this point, if you came into this chapter without any knowledge of XML, I can only assume you are overwhelmed. If you did have a basic understanding of XML, but not of LINQ to XML, I hope I have made this understandable for you. The power and flexibility of the LINQ to XML API is quite intoxicating. While writing this chapter and creating the examples, I would find myself lulled into a state of XML euphoria, a state without the underlying desire to avoid using “real” XML, only to find myself back at my day job planning on taking advantage of the simplicity LINQ to XML offers, despite the fact that my work project cannot use it because it has not been released yet. So many times I thought, Rattz_789-3.book Page 335 Tuesday, October 16, 2007 2:21 PM 336 CHAPTER 9 ■ ADDITIONAL XML CAPABILITIES if I could just use functional construction to whip up this piece of XML, only to find the reality of the situation causing me to use my standby XML library, the String.Format method. Don’t chastise me for taking the easy way out. As I previously mentioned, I was at a Microsoft seminar where the presenter demonstrated code that built XML in a similar manner. Having written the many examples in this chapter and the previous LINQ to XML chapters, I can’t tell you how excited I will be to actually use the LINQ to XML API in my real production code. The fact is that with LINQ to XML, because XML creation is largely based on elements rather than documents coupled with the capability of functional construction, creating XML is painless. It might even be fun. Combine the easy creation with the intuitive traversal and modification, and it becomes a joy to work with, considering the alternatives. Having all this ease of use working with XML piled on top of a powerfully flexible query language makes LINQ to XML my personal favorite part of LINQ. If you find yourself dreading XML or intimi- dated to work with it, I think you will find the LINQ to XML API quite pleasant. Rattz_789-3.book Page 336 Tuesday, October 16, 2007 2:21 PM [...]... s.Field(0, DataRowVersion.Current)) Single(); Console.WriteLine("Anthony's Id retrieved with prototype 3 is: {0}", id); // Using prototype 4 id = (from s in seq1 where s.Field("Name") == "Anthony Adams" select s.Field(dt1.Columns[0])) Single(); Console.WriteLine("Anthony's Id retrieved with prototype 4 is: {0}", id); // Using prototype 5 id = (from s in seq1 where s.Field("Name")... retrieved with with with with with with prototype prototype prototype prototype prototype prototype 1 2 3 4 5 6 is: is: is: is: is: is: 7 7 7 7 7 7 359 Rattz _78 9-3.book Page 360 Tuesday, October 16, 20 07 2:21 PM 360 CH APT ER 10 ■ LI NQ TO D AT AS ET O PE RAT ORS Before moving on to the SetField operator, I want to provide an example demonstrating one of the prototypes that allows you to specify the... compiled, or a mapping file must be created This means that performing LINQ queries with LINQ to SQL on a database unknown until runtime is not possible Additionally, LINQ to SQL only works with Microsoft SQL Server What is a developer to do? The LINQ to DataSet operators allow a developer to perform LINQ queries on a DataSet, and since a DataSet can be obtained using normal ADO.NET SQL queries, LINQ to DataSet... DataRowVersion.Current)) Single(); Console.WriteLine("Anthony's Id retrieved with prototype 1 is: {0}", id); // Using prototype 2 id = (from s in seq1 where s.Field("Name") == "Anthony Adams" select s.Field("Id", DataRowVersion.Current)) Single(); Console.WriteLine("Anthony's Id retrieved with prototype 2 is: {0}", id); // Using prototype 3 id = (from s in seq1 where s.Field("Name")... string anthonysClass = (from s in seq1 where s.Field("Name") == "Anthony Adams" from c in seq2 where c["Id"] == s["Id"] select (string)c["Class"]) SingleOrDefault(); Console.WriteLine("Anthony's Class is: {0}", anthonysClass != null ? anthonysClass : "null"); There are a couple of things worth pointing out about that query First notice the line that is bold There, I am indexing into...Rattz _78 9-3.book Page 3 37 Tuesday, October 16, 20 07 2:21 PM PART 4 ■■■ LINQ to DataSet Rattz _78 9-3.book Page 338 Tuesday, October 16, 20 07 2:21 PM Rattz _78 9-3.book Page 339 Tuesday, October 16, 20 07 2:21 PM CHAPTER 10 ■■■ LINQ to DataSet Operators W hile I haven’t covered LINQ to SQL yet, let me mention at this time that to utilize LINQ to SQL for a given database, source... s.Field("Name") == "Anthony Adams" select s.Field("Id")) Single(); Console.WriteLine("Anthony's Id retrieved with prototype 5 is: {0}", id); // Using prototype 6 id = (from s in seq1 where s.Field("Name") == "Anthony Adams" select s.Field(0)) Single(); Console.WriteLine("Anthony's Id retrieved with prototype 6 is: {0}", id); Nothing here is very significant I declare the array... shown in Listing 10 -7 Listing 10 -7 Comparing 3 to 3 Console.WriteLine("(3 == 3) is {0}.", (3 == 3)); The following is the result of this code: (3 == 3) is True There is absolutely no surprise there But what happens when an integer gets boxed? Let’s examine the code in listing 10-8 and look at the results Listing 10-8 Comparing 3 Cast to an Object to Another 3 Cast to an Object Console.WriteLine("((Object)3... join them using their common Id column, which I will retrieve by indexing into the DataRow with the column name, which is Id Listing 10-9 shows the code Listing 10-9 Joining Two Value-Type Columns by Indexing into the DataRow Student[] students new Student { Id new Student { Id new Student { Id new Student { Id }; = = = = = { 1, Name = "Joe Rattz" }, 7, Name = "Anthony Adams" }, 13, Name = "Stacy Sinclair"... objects using the number of columns in a row and the static data type of each column, and then using the IComparable interface on each column if its dynamic data type implements the IComparable interface, or calling the static Equals method in System.Object if it does not Prototypes The Distinct operator has one prototype I will cover The Distinct Prototype public static IEnumerable Distinct ( . this ease of use working with XML piled on top of a powerfully flexible query language makes LINQ to XML my personal favorite part of LINQ. If you find yourself dreading XML or intimi- dated to. with it, I think you will find the LINQ to XML API quite pleasant. Rattz _78 9-3.book Page 336 Tuesday, October 16, 20 07 2:21 PM ■ ■ ■ PART 4 LINQ to DataSet Rattz _78 9-3.book Page 3 37 Tuesday, October. be obtained using normal ADO.NET SQL queries, LINQ to DataSet allows LINQ queries over any database that can be queried with ADO.NET. This provides a far more dynamic database-querying interface

Ngày đăng: 06/08/2014, 08:22

TỪ KHÓA LIÊN QUAN

w