Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 79 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
79
Dung lượng
438,34 KB
Nội dung
374 | Chapter 13: XML Dim attrData As XmlAttribute attrData = products.CreateAttribute("ID") attrData.Value = "652" supplier.SetAttributeNode(attrData) So, this is nice and all, but what if you already have some XML in a file, and you just want to load it into an XmlDocument object? Simply use the XmlDocument object’s Load method. Dim products As XmlDocument products = New XmlDocument products.Load("c:\products.xml") For those instances where you just want to read or write some XML from or to a file, and you don’t care much about manipulating it in memory, the XmlTextReader and XmlTextWriter classes let you quickly read and write XML data via a text stream. But if you are going to do things with the XML data in your program, the Load and Save methods of the XmlDocument object are a better choice. Finding Needles and Haystacks In our sample data, all of the products appear in supplier groups. If we just want a list of products, regardless of supplier, we ask the XmlDocument object to supply that data via an XmlNodeList object. Dim justProducts As XmlNodeList Dim oneProduct As XmlNode ' First, get the list. justProducts = products.GetElementsByTagName("product") ' Then do something with them. For Each oneProduct In justProducts ' Put interesting code here. Next oneProduct MsgBox("Processed " & justProducts.Count.ToString( ) & _ " product(s).") For a more complex selection of nodes within the document, the System.Xml.XPath namespace implements the XPath searching language, which gives you increased flexibility in locating items. The Visual Studio documentation describes the methods and searching syntax used with these classes. Schema Verification An XmlDocument object can hold any type of random yet valid XML content, but you can also verify the document against an XSD schema. If your XML document refers to an XSD schema, includes a DTD, or uses XDR (XML Data Reduced schemas, sim- ilar to XSD), an XmlReader, when configured with the appropriate XmlReaderSettings, will properly compare your XML data against the defined rules, and throw an excep- tion if there’s a problem. Using XML in .NET: The New Way | 375 Dim products As New XmlDocument Dim xmlRead As XmlTextReader Dim withVerify As New XmlReaderSettings Dim xmlReadGood As XmlReader ' Open the XML file and process schemas ' referenced within the content. withVerify.ValidationType = ValidationType.Schema xmlRead = New XmlTextReader("c:\temp\products.xml") xmlReadGood = XmlReader.Create(xmlRead, withVerify) ' Load content, or throw exception on ' validation failure. products.Load(xmlReadGood) ' Clean up. xmlReadGood.Close( ) xmlRead.Close( ) XML Transformations XSL Transformations are no more difficult than any of the other manipulations of XML. Just as there are many ways to get XML source data (from a file, building it by hand with XmlDocument, etc.), there are many ways to transform the data. If you just want to go from input file to output file, the following code provides a quick and effi- cient method. It uses a System.Xml.Xsl.XslCompiledTransform instance to perform the magic. ' Above: Imports System.Xml.Xsl Dim xslTrans As XslCompiledTransform ' Open the XSL file as a transformation. xslTrans = New XslCompiledTransform( ) xslTrans.Load("c:\convert.xsl") ' Convert and save the output. xslTrans.Transform("c:\input.xml", "c:\output.txt") Using XML in .NET: The New Way When Visual Basic first came out, no one had even heard of XML. But now it’s everywhere. It’s like that black oozing stuff that bonds with Peter Parker in Spider- man 3, but without all the creepy special effects. And now in Visual Basic 2008, XML is part of the language syntax itself. When will it end? It turns out that making XML part of the language is pretty cool. In the old-way sec- tion a few pages ago, I showed you some code that created the XML product list for “Chai.” The XML content was 11 lines long, but it took nearly 50 lines of source code to produce it. But you can build that same XML content using the new way in pretty close to the final 11 lines. 376 | Chapter 13: XML Dim chaiItem As System.Xml.Linq.XDocument = _ <?xml version="1.0"?> <productList> <! We currently sell these items. > <supplier ID="652" fullName="Beverages R Us"> <product ID="1" available="Yes"> <productName>Chai</productName> <category>Beverages</category> <unitPrice>18.00</unitPrice> </product> </supplier> </productList> How about that! Except for the first declaration line, the content is identical to the final XML. The new XML Literals feature makes building XML documents a snap. The content gets stored in the new XDocument object, part of the System.Xml.Linq namespace. If you want to store just a section of XML instead of the entire docu- ment, use the XElement class instead. Dim productSection As System.Xml.Linq.XElement = _ <product ID="1" available="Yes"> <productName>Chai</productName> <category>Beverages</category> <unitPrice>18.00</unitPrice> </product> If you have type inference enabled in your program (Option Infer On), you don’t even need to tell Visual Basic whether it’s an XElement or an XDocument. Dim productSection = _ <product ID="1" available="Yes"> <productName>Chai</productName> <category>Beverages</category> <unitPrice>18.00</unitPrice> </product> Just like the XmlDocument class, the XDocument class includes Load and Save methods to manage file-based XML. Embedded XML Expressions Including XML in your source code is amazing stuff, but it will stay amazing only if you always sell Chai for $18.00 per unit. Real XML content is usually going to come from variable data. And despite the XML “Literal” name, XML Literals can include nonliteral variable content through embedded XML expressions. Whenever you want to add data from a variable or expression to your XML text, you use the special <%= and %> symbols to offset your custom data. Dim productID As Integer = 1 Dim productName As String = "Chai" Dim productCategory As String = "Beverage" Dim productPrice As Decimal = 18@ Dim isAvailable As Boolean = True Using XML in .NET: The New Way | 377 Dim productSection = _ <product ID=<%= productID %> available=<%= Format(isAvailable, "Yes/No") %>> <productName><%= productName %></productName> <category><%= productCategory %></category> <unitPrice><%= productPrice %></unitPrice> </product> Of course, to generate an entire catalog of products, you’re going to be doing a lot of typing. In Chapter 17, I’ll introduce some additional ways to embed XML expres- sions with entire tables of data. XML Axis Properties Earlier in the chapter, in “Finding Needles and Haystacks,” I showed you how you could access specific sections of old-style XML documents. The new-style XML objects also include ways to scan and access portions of the XML tree. These are called XML axis properties, and they come bundled up in three syntax-friendly varieties: Child-member axis You can access an immediate child tag of any XElement by using the child’s name as a member of the parent object, enclosing the child’s name in a set of angle brackets: childElement = parentElement.<childName> Descendent-member axis A variation of the child-member axis syntax lets you access named members at any depth within a parent element. Instead of using just a single dot ( .) between the parent and child names, use three dots: setOfElements = parentElement <descendentName> Attribute axis Access any attribute of an element by treating the attribute name as a member name, prefixing the attribute name with the @ character: attributeValue = parentElement.@attributeName The following block of code scans through the product list we designed early in the chapter, displaying the ID number and name of each product on the console: For Each oneProduct In allProducts <product> Console.WriteLine(oneProduct.@ID & ": " & _ oneProduct.<productName>.Value) Next oneProduct This code uses all three axis styles. The For Each Next loop scans through all matching <product> entries by using a descendent-member axis. In each matching product element, the code accesses the ID attribute using an attribute axis, and gets the name of the product using a child-member axis, along with the Value property of the returned child element. The output looks like this: 1: Chai 2: Chang 3: Aniseed Syrup 378 | Chapter 13: XML For more advanced ways of scanning through XML content and selecting child ele- ments based on complex criteria, see Chapter 17. Namespaces and Schemas for XML Literals As with the old way of managing XML, the new way lets you include namespaces in your XML content. To add an XML namespace prefix, simply include it in the con- tent as you would in any other XML scenario. Dim foodItems = _ <?xml version="1.0"?> <menu:items xmlns:menu="http://www.timaki.com/menu"> <menu:item> <menu:name>Pizza</menu:name> <menu:price>12.99</menu:price> </menu:item> <menu:item> <menu:name>Breadsticks</menu:name> <menu:price>1.99</menu:price> </menu:item> </menu:items> You can also define the namespace, the xmlns part, by using a variation of the Visual Basic Imports statement. Imports <xmlns:menu="http://www.timaki.com/menu"> later Dim foodItems = _ <?xml version="1.0"?> <menu:items> and so on Visual Basic will still insert the xmlns definition at the right place in the XML con- tent. It’s actually stored as a distinct XNamespace object within the XDocument or XElement. To generate an XNamespace object for your own use, Visual Basic includes a new GetXmlNamespace function. Dim justTheNamespace = GetXmlNamespace(menu) Summary There are a lot of useful features in the various System.Xml namespaces, and you can manage complex data in very effective ways. It’s not always the most efficient way to manage data, but if you have structured hierarchical data, it may be the most direct and clearest method. Although XML lurks everywhere in the .NET Framework, and in all applications written using .NET, you could actually write large and interesting applications without Project | 379 looking at a single line of XML content. Even if your application needs to interact with XML content, the new XML features included in Visual Basic make managing XML as easy as typing the content directly into Notepad. Wait a minute, that’s not easy or fun. But it’s a lot better than piecing the content together through string concatenation. XML is a very useful and flexible data format that is here to stay. Although it will always lack the speed of more compact data standards, its benefits are numerous. There has been talk of introducing a “binary XML” format as a standard, although nothing concrete has come of it yet. If binary XML does become a standard, you will likely continue to use the same classes and methods introduced in this chapter, with the possible addition of an OutputFormat (“Text” or “Binary”) property. Project The administrator of the Library system will want to see statistics and information at a glance, or run various reports that provide meaningful summary or detail views of system data. Although as a programmer I could try to add every conceivable type of report that the user may need, I have learned from experience that this is not possi- ble. Users always want the moon, usually in the form of some weird esoteric report that I know they will use once and never look at again (although they will call once a year asking for the same report to be written again). I don’t like recompiling and rereleasing the entire application every time a user needs a new report. Instead, I keep the reports outside the application, stored as separate programs. Then, from one form in the main application, I make all of those external reports available in a nice convenient list. To implement this generic feature, I use a report configuration file, a simple XML file that contains information on the available reports, and how to run them. I want my selection list to have indented items so that I can visibly group reports for conve- nience. To do this, I will make my XML file into an unlimited depth hierarchy, with each level representing a further level of displayed indent. For instance, let’s say I wanted the following outline of reports (with report group titles in bold): Detail Reports Daily Report Monthly Reports Monthly Value Monthly Inventory Summary Reports Inventory Summary 380 | Chapter 13: XML The XML configuration would follow this structure: <Group name="Detail Reports"> <Item name="Daily Report"/> <Group name="Monthly Reports"> <Item name="Monthly Value"/> <Item name="Monthly Inventory"/> </Group> </Group> <Group name="SummaryReports"> <Item name="Inventory Summary"/> </Group> Of course, this is greatly simplified (not to mention noncompliant) XML. In addi- tion to the hierarchy, I also want to include support for a variety of reporting meth- ods. To keep things simple, the Library Project will include three types of reports: Built-in reports The application includes a limited number of reports that are permanently built into the main application (assembly). The reports are numbered, starting from 1, and at this time I have five reports in mind. The designer of the XML configura- tion file can choose to include these in the display of reports or not by simply including or not including them in the file. In the absence of a configuration file, these reports will appear in the list by default. In addition to the report number (1 to 5), each entry has a display text and a long description. Application reports These reports are separate and distinct EXE files, and are started via standard application initiation methods. Each entry includes a display text, the full path to the application, optional arguments, a flag to pass the identity of the user ini- tiating the report, and a long description. URL reports These reports are simple calls to web pages, or any other valid URL. For instance, you could include a report entry that does a “mailto:” to the local orga- nization’s help desk. Each entry includes the display text, the URL itself, and a long description. The project activities in this chapter involve both coding and documentation of the new external resource (the XML file format). PROJECT ACCESS Load the Chapter 13 (Before) Code project, either through the New Project tem- plates or by accessing the project directly from the installation directory. To see the code in its final form, load Chapter 13 (After) Code instead. Project | 381 Update Technical Documentation First, let’s add clear documentation on the structure of the XML configuration file. There is no easy way to communicate the structure of an XML file to an ordinary user. Although such documentation is a requirement, hopefully the application will also include a tool to let an administrator build the configuration file. Such a pro- gram, sadly, is not included in this book’s project. It is left as an exercise for the reader. (I always wanted to say that.) Report Configuration File The library application can be configured to run any number of reports through the Reports form. The list of available reports is managed through an XML report configuration file, a file containing “groups” and “items.” All items are reports, and appear within a group. You can nest groups within groups to any depth, and the list of reports displayed in the Library program will indent each subordinate group to help the user see the organization of the reports. There is no limit to the nesting of groups. The root element of the XML file must be named <reportList>, and it may con- tain any number of <reportGroup> and <reportItem> data elements: • <reportItem>: Represents a single report entry. This entry has one required attribute, and up to five subordinate data elements depending on the setting of the attribute: — type (attribute): Set to one of the following values: • built-in: Run one of the built-in programs. This type of report uses the <displayText>, <reportPath>, and <description> data elements. • program: Runs a separate EXE program. This type of report uses the <displayText>, <reportPath>, <reportArgs>, <reportFlags>, and <description> data elements. • url: Starts a URL, such as a web page or a “mailto” email to a recipient address. This type of report uses the <displayText>, <reportPath>, and <description> data elements. — <displayText>: A short name or description for this report, as it will appear in the list of report choices. This element is required for all types of reports. — <reportPath>: The full path, URL, or number of the report, depending on the type of report. For program (EXE) reports, this is the full UNC or driver letter- based path to the report, without additional arguments. For built-in reports, this is a report number, from 1 to 5 (values and their meanings are listed later in this section). For URL reports, this is the actual URL, as in “http:// mysite.com/myreport.aspx”or“mailto:helpdesk@mysite.com.” This element is required for all types of reports. 382 | Chapter 13: XML — <reportArgs>: For program (EXE) reports, this entry includes any command- line arguments to be included when running the program. This element is valid only for program (EXE) reports, and is always optional. — <reportFlags>: For program (EXE) reports, this entry indicates the optional flags that should be appended to the application command as arguments. At this time, the only flag is the U flag. When this element is set to U, the argu- ment -u userid is appended to the command string (where userid is the user’s login ID, from the database field UserName.LoginID). This element is valid only for program (EXE) reports, and is always optional. — <description>: This is a longer, verbose description of the report, up to about 200 characters, which will appear on the Report form when the user selects the report from the list. This description should assist the user in selecting the right report. This element is valid for all types of reports, but is always optional. • <reportGroup>: Represents a category group, used to visibly group and indent reports in the display list. This element must contain exactly one <displayText> element, but may contain any number of <reportItem> or <reportGroup> elements: — <displayText>: A short name or description for this group, as it will appear in the list of report choices. This element is required. When using the “built-in” report type, the <reportPath> element is set to one of the following integer values: • 1—Items Checked Out Report • 2—Items Overdue Report • 3—Items Missing Report • 4—Fines Owed by Patrons Report • 5—Library Database Statistics Report This technical description appears in the Technical Resource Kit document, origi- nally developed in Chapter 4. Create Report Entry Class With .NET’s ability to store whole objects as ListBox items, we can create a custom class that contains all the information needed to select and run a report from the list of reports. This class is fairly simple, with nothing but basic public fields, plus an overridden ToString function, used by the ListBox control to properly display each list item. In the Library Project, add a new class file named ReportItem.vb through the Project ➝ Add Class menu command. Add the following enumeration to the file, but add it Project | 383 outside the Class End Class boundaries. This enumeration indicates what type of entry each list item represents. INSERT SNIPPET Insert Chapter 13, Snippet Item 1. Public Enum ReportItemEnum ' The type of item in the report select list. GroupLabel = 0 BuiltInCheckedOut = 1 BuiltInOverdue = 2 BuiltInMissing = 3 BuiltInFinesOwed = 4 BuiltInStatistics = 5 ExeProgram = 6 UrlProgram = 7 End Enum To this same file, add the members of the ReportItem class. This class contains all the information we need to run reports loaded from the configuration file. INSERT SNIPPET Insert Chapter 13, Snippet Item 2. ' Instance of report selection items used ' in the ReportSelect form. Public ItemType As ReportItemEnum Public Indent As Integer ' Indent level. Starts with 0. Public DisplayText As String Public ReportPath As String ' ExeProgram / UrlProgram only Public ReportArgs As String ' ExeProgram only Public Description As String Public Overrides Function ToString( ) As String ' Display an indented string. Prepend with spaces. Return StrDup(Indent * 5, " ") & DisplayText End Function Design the Report Form Librarians and administrators use the Select Report form (see Figure 13-2) to view reports. The form includes a ListBox control that displays all reports and report groups, a Run button that starts a report, and a Close button that returns the user to the main form. A label displays the full description of a report, when available, just below the ListBox. [...]... settings have been giving programmers at least some level of angst since Windows first appeared But a new and improved settings system, first added to Visual Basic in 2005, seeks to change all that Settings in Visual Basic 2008 The settings system in Visual Basic 2008 is a multifile, XML-based, strongly typed, and easy-to-manage configuration approach Its file-focused methodology includes these features and... Settings in Visual Basic 2008 | 395 Figure 14-1 The Settings panel with no defined settings What happens when you add a new setting to your Visual Basic project? Let’s find out I’ll add two settings to a new Windows Forms project: an Integer named WarningLimit, and a System.Drawing.Font named NoticeFont (see Figure 14-2) Figure 14-2 The Settings panel with two new settings As you already know, Visual Studio... Write BasicReportCheckedOut( ) Case ReportItemEnum.BuiltInOverdue ' - Items Overdue ' TODO: Write BasicReportOverdue( ) Case ReportItemEnum.BuiltInMissing ' - Items Missing ' TODO: Write BasicReportMissing( ) Case ReportItemEnum.BuiltInFinesOwed ' - Fines Owed by Patrons ' TODO: Write BasicReportFines( ) Case ReportItemEnum.BuiltInStatistics ' - Library Database Statistics ' TODO: Write BasicReportStatistics(... quite clear Visual Studio generates two properties within the My.MySettings class, properties named—amazingly enough— WarningLimit and NoticeFont Here’s the property entry for NoticeFont: Public Property NoticeFont( ) As Global.System.Drawing.Font Get Return CType(Me("NoticeFont"), _ Global.System.Drawing.Font) End Get Set Me("NoticeFont") = value End Set End Property Settings in Visual Basic 2008 | 397... drop-down list, choose the Scope (User or Application), and enter its Value using whatever value editor is available for the selected type The Type list includes many default selections, including the basic Visual Basic data types, fonts, colors, and drawing-related sizes Also included is a “(Connection string)” type that, when selected, enables a Connection Properties string builder in the Value column It’s... Text: LabelReports 8, 8 &Reports AllReports ListBox (Name): Location: Size: AllReports 8, 24 392, 160 LabelDescription Label (Name): Location: Text: LabelDescription 8, 200 Report Description FullDescription Label (Name): AutoSize: Location: Size: Text: UseMnemonic: FullDescription False 32, 224 368 , 64 Report not selected False ActRun Button (Name): DialogResult: Location: Size: Text: ActRun None... followed by Settings.settings, you will find that this XML file has its own Visual Basic source code file, Settings.Designer.vb If you open the Settings.Designer.vb file, you find the following partial code: Namespace My Partial Friend NotInheritable Class MySettings Inherits Global.System.Configuration _ ApplicationSettingsBase 3 96 | Chapter 14: Application Settings . with Peter Parker in Spider- man 3, but without all the creepy special effects. And now in Visual Basic 2008, XML is part of the language syntax itself. When will it end? It turns out that making. 392, 160 LabelDescription Label (Name): LabelDescription Location: 8, 200 Text: Report Description FullDescription Label (Name): FullDescription AutoSize: False Location: 32, 224 Size: 368 , 64 Text:. you have type inference enabled in your program (Option Infer On), you don’t even need to tell Visual Basic whether it’s an XElement or an XDocument. Dim productSection = _ <product ID="1"