Thunderclap, the Newsletter of Rolling Thunder
Computing
Volume 4, Number 3 Summer 2002
In this issue:
Feature Article: .NET Reflection API For
Finding Element IDs in XML Wrapper Classes
Blatant Self-Promotion: Public Class
on ACORD XML in New York, Public Class on .NET for the Insurance Industry, .NET in Iceland, In-House Training
Classes on ACORD XML and .NET
New Book: Second
Edition of Introducing
Microsoft .NET
The Internet Chuckle: Web Pages That Suck
Contest with Prizes: No More
Results of Last Contest: Jeopardy
Subscription Information
This article requires familiarity with .NET XML serialization wrapper classes, which I discussed in an earlier newsletter. Click here to read it if you haven't already.
I was teaching a class on ACORD XML and demonstrating the document wrapper classes that .NET can generate from a schema. This always gets an "Ooooh, cool!" response from students, who are reeling in shock from the thought of having to write complex logic using XPath expressions in a DOM parser. They think it's the greatest thing since caffeinated water. Until one day, one sharp student, more suspicious and cynical than the others (a guy after my own heart), said, "Yeah, Plattski, that's fine. But if I have an IDREF element on a wrapper class object, how do I find the element to which it refers? I don't see the NodeFromID method that I have in DOM. If I can't do that, then this wrapper class business is just an expensive paperweight. If you expect to come back here and teach us .NET, you'll have to figure that one out." I like a challenge, especially when there's a potential training gig attached, so I figured I'd work on this one on the plane ride back to the East Coast. We picked up a head wind, so I just had time to finish it before the seatbelt light came back on.
The student was worried about the following situation. You can't, and shouldn't, represent every possible relationship between elements in an XML document by means of the containment hierarchy. You often need a way to make one element refer to another somewhere else in the document, which I call a "sideways link" or "lateral link". XML contains the ID and IDREF types of attributes to support this situation. An element that wants to be a target for lateral links contains an attribute of XML data type ID. This is the element's unique identifier within the document, its primary key in database terms. This attribute's value must be unique among all ID attributes in the entire document, regardless of the attribute's name or the element on which it appears, and its value must begin with a letter or an underscore. A validating parser will enforce these restrictions. . The declaration of an ID attribute in an XML schema, and the use of that attribute in an XML document are shown in the following table:
Definition of ID attribute |
Use of ID attribute |
<xsd:element name="Party"> <xsd:complexType> (other elements omitted) <xsd:attribute name="id" type="xsd:ID" use="required"/> </xsd:complexType> </xsd:element> |
<Party id = "Party_1264" > <FullName> Racer, Speed </FullName> </Party> |
An element that wants to refer to the first one will contain an attribute of XML data type IDREF. This must contain the value of an ID attribute that exists in the document. Think of this as the foreign key in database terms. Any number of IDREF attributes can point to the same ID, just as any number of foreign keys can reference a primary key. The declaration of an IDREF attribute in an XML schema, and its use in an XML document fragment are show below.
Definition of IDREF attribute |
Use of IDREF attribute |
<xsd:element
name="LifeParticipant"> <xsd:complexType> <xsd:attribute name="PartyID" type="xsd:IDREF"/> </xsd:complexType> </xsd:element> |
<LifeParticipant PartyID = "Party_1264" />
|
In this case, the LifeParticipant element contains an attribute that refers to the element that contains an attribute of type ID whose value is "Party_1264". By convention, we usually give the ID attribute (the unique identifier of an element, remember) the name "id" (note the lower case), but we don't have to. The names of IDREF attributes usually have some indication of the sort of element to which they refer (in this case, the party that is participating in the life insurance policy, such as the insured or beneficiary), but again, this is purely conventional and does not affect the underlying rules of the XML language.
Once we have our IDREF attribute value, the programming problem is to find the element to which it refers, the "target element". In this case, we read the IDREF attribute from the LifeParticipant element, which tells us that we want to find the Party element whose ID is "Party_1264" so we can read its name and address and other Party properties. A DOM parser generally contains a method called NodeFromID (or something similar, it varies from one implementation to another) allowing a programmer to retrieve this node with a single function call. But our XML wrapper class documents are not in a DOM parser, and we don't want to put them in one. We like the fact that they are plain and simple .NET objects; we like the fact that their XML document-ness has been abstracted away. But we need some simple and easy way of dereferencing cross links. How can we do this?
Fear not! As Jay Ward's cartoon character Mr. Peabody always said, "As usual, Sherman, I have a plan." Regardless of the class of the wrapper object, we can use .NET's reflection API to examine it at runtime and determine if it has an ID attribute, and if so, what its value is. We can also use the reflection API to examine the objects that it contains and recursively search our way through the entire XML document. It's actually simpler than it sounds, and the explanation takes more space than the code.
Every .NET object contains metadata, emitted by the language compiler, describing its contents and capabilities. The writer of the object doesn't have to do any work to make it happen, so he can't omit it, and he can't screw it up. You can view an object's metadata using the MSIL disassembler tool that comes with the SDK, ILDASM.EXE. The .NET reflection API allows client programs to read this metadata and use it to access an object's properties, fields and methods.
How do we know which object field contains the value of the ID attribute? We could look for fields named "id". But if anyone ever violated this naming convention, our search program would stop working. Although ACORD XML uses this convention throughout, this could happen if we mixed ACORD XML with another problem domain vocabulary (say, medical, when we start adding lab results to the life standard) that used a different naming convention for its ID attributes. So we need a way of identifying all ID attributes regardless of their names.
Fortunately, this is easy to do. When we import the schema into .NET and generate the wrapper class, each wrapper class variable that represents an XML attribute is marked with the .NET programming attribute XmlAttributeAttribute. This decoration tells the XML serializer to read or write that variable as an attribute rather than an element. (Again, if you're not familiar with this, read my newsletter from last fall to understand the .NET XML serialization and wrapper class mechanism.) When the XML attribute is of type ID, then the .NET programming attribute contains the notation DataType:="ID". The wrapper class looks like this:
Public
Class Party <System.Xml.Serialization.XmlAttributeAttribute(
_
Form:=System.Xml.Schema.XmlSchemaForm.Unqualified, _
DataType:="ID")> _
Public id As String
So to locate the XML attributes of type ID, we need to find the object fields marked with .NET programming attributes of type XmlAttributeAttribute that contain the value DataType:="ID". Again, it's actually easier to do than it is to say, particularly if you've had a couple of drinks.
I wrote a sample program that demonstrates the use of the reflection API to find an object containing an ID attribute with the specified value. The program opens an XML document and deserializes its contents into a wrapper class object (which I generated from the XMLife schema). When you enter the desired ID value, the program uses reflection to search through the wrapper class object, including all of its contained objects, to find the element with the desired ID. After it's found the object, it will fetch again use reflection to fetch the value of the field of the object whose name you specify. In the example below, it searches the file that the user gives it for an object whose ID is "Party_1264". When it finds that element, it uses reflection to read and display its FullName property, in this case, "Speed Racer". The program is shown below. You can download the source code by clicking here.
The client code is quite simple. I've written the search into a component, which the client creates and calls. Thus:
' Create the object that knows how to search for an' Tell the object to
search for an object having the
' id attribute value specified by the user
The server code is a little more complex, but you'd be surprised how simple it actually is. Here's how it works. The key to reflection is the class System.Type. This is ambiguously-named object contains methods for reading and writing the properties, fields (member variables), events, constructors, and methods of the object that it describes. Think of it as a "class descriptor" and you'll have the right mental model. Out program calls the method GetType, which lives on the universal base class System.Object from which all other classes in .NET derive. This returns a Type object describing the object from which you call it. Our program then calls the method Type.GetFields, which returns an array of FieldInfo objects, each of which describes a field of the object. I loop through this collection to examine each field. The FieldInfo object, in turn, contains a method called GetValue, which returns the value of that field. (I get the value of the field before I check to see if it is an ID field because I use the value later in the program, for recursive navigation along the containment hierarchy that I don't show here because it's boring). Now I want to see if the field is marked with the XmlAttributeAttribute decoration. I do that using the static method System.Attribute.GetCustomAttribute, passing it the field and the type of attribute that I want to fetch. If the return value is Nothing, then I know the field is not marked with the .NET attribute, which means that it does not represent an XML attribute. If it isn't Nothing, then it is an XML attribute, so I check to see if contains the DataType ID. And if that works, then I know I have an attribute of type ID, so I compare its value to the one that the caller gave me to look for. If that works, then I've matched the object, and I return it and stop searching. If not, I continue the search through the rest of the object's fields, working my way down through the containment hierarchy (boring code not shown, but available online). This explanation may seem long winded, but if you check the code listing, you'll find only 10 executable statements.
Public
Class Class1' Get type of supplied object
Dim ThisObjectType As System.Type = ThisObject.GetType
' Get all the fields of the object
Dim ThisObjectFields As
System.Reflection.FieldInfo()
ThisObjectFields =
ThisObjectType.GetFields
' Loop through each one
Dim
fi As System.Reflection.FieldInfo
For
Each fi In
ThisObjectFields
' Check if it's a value type. These we don't bother to
' enumerate,
because an ID can't be one, and a value type
' can't
contain anything else
If (fi.FieldType.IsValueType = False) Then
' Get the value of the field
Dim Value As Object
' See if field contains the attribute that says it serializes as an XML attribute
Dim attr As System.Xml.Serialization.XmlAttributeAttribute
' If it does, then check to see if it's of type ID
If (Not attr Is Nothing) Then
' If it is, then check to see if it has the ID value we've been asked to find.
If (CStr(Value) = IdValue) Then
<close all If statements, continue recursive search, etc.>
This technique is easy for a programmer to call. It's potentially much more efficient than the NodeFromID in the generic DOM parser because it works recursively off the node you pass it, so it doesn't have to trace down paths that you know aren't useful. You can certainly start at the root of the document if you want, as this sample does, but if you have information that allows you to prune the search tree, this technique will also give a performance benefit.
This is one more demonstration why .NET is the best platform for writing ACORD XML code. I'd like to train you in it. I've just developed a new class on .NET for the Insurance Industry to go with my other .NET offerings. I'm giving a public offering of it in November, or you can have it in-house at your company. Click here to find out more about it, then call me to set up your class.
We'll continue our discussion of .NET in the next issue. Enjoy playing with your new attribute program. Give me a call if I can help you out. Until next time, as Red Green would say, "Keep your stick on the ice."
Public class on ACORD XML for Insurance in New York September 23 - 27 (and Boston Jan 27-31, 2003, and San Francisco April 1-5, 2003). SAME CLASS AVAILABLE IN-HOUSE AT YOUR COMPANY.
Two instructors combine to bring you the best of ACORD XML training. Tana Sabatino, former head of standards for ACORD teaches her 1-day XMLife data model class on Monday Sep 23. Then David Platt, long-time instructor in ACORD XML (author of this newsletter, in case you hadn't figured that out by now, and all-around great guy) teaches his 4-day class ACORD XML in Depth. Full syllabus and registration information are online at http://www.rollthunder.com/xmlpublicframe.htm. We're offering a 10% early bird discount for registrations received before August 15.
Public Class on .NET for the Insurance Industry in Boston Dec 9-13, 2002. SAME CLASS AVAILABLE IN-HOUSE AT YOUR COMPANY.
.NET is here, and it's hot. It changes everything in the software business, and you can't afford to be without it. Rolling Thunder Computing now offers in-house training classes on .NET, using my book as the text. I've split it up into customized offerings, such as .NET for Existing 3-tier Microsoft Programmers, .NET Framework Serious Geekery, .NET Web Programming, and .NET for the Insurance Industry. See the syllabi at http://www.rollthunder.com/DotNetNewPublicClassFrame.htm
Public class on .NET in Iceland, September 2 - 6
I'm back at the University of Iceland in Reykjavik at the beginning of September. If you live in Iceland, here's your chance to hear about .NET from the guy who wrote the book on it. If you don't, why not consider taking a trip there? The class is taught completely in English. Iceland's a great place for a vacation, especially this time of year. The tuition is only about US$1500, less than in the US, and you'll get a great vacation too. You'll find a short description in Icelandic here and the full description in English here.
Public Class on Programming .NET at Harvard Extension this fall
I'll be back teaching at Harvard Extension this fall, after a two-year hiatus. The course will be a broad survey of all of .NET, with lots of programming homework. It will meet on Monday nights at 7:30, starting September 23. I don't know the room yet, and I haven't worked out the full syllabus yet. Announcements will be made on my web site, http://www.rollthunder.com. Anyone interested in being a teaching assistant for the class, send me e-mail at dplatt@rollthunder.com.
5-day In-House Training Class on .NET or .NET for Insurance
.NET is here, and it's hot. It changes everything in the software business, and you can't afford to be without it. Rolling Thunder Computing now offers in-house training classes on .NET, using my book as the text. I've split it up into customized offerings, such as .NET for Existing 3-tier Microsoft Programmers, .NET Framework Serious Geekery, .NET Web Programming, and .NET for the Insurance Industry. See the syllabi at http://www.rollthunder.com/DotNetNewClassFrame.htm
New Book: Introducing Microsoft .NET, Second Edition
Updated to V1.0 Release, with 5 New Chapters Added
Sample code now in both VB and C#
by David S. Platt, President of Rolling Thunder Computing
Published by Microsoft Press
ISBN 0-7356-1571-3
Microsoft finally shipped .NET, so I decided to update my book on it, and add lots of new material that I didn't have time to cover before. I've brought all the material up to date with the final RTM version of the product. I've added enhanced material so several of the previous chapters, a sample of which forms this newsletter's feature article. And I've added 6 new chapters, as you can see in the table of contents below. And as many readers asked for, I've written all the sample code in both VB and C#. If you liked the first edition, you'll probably like the second one as well. I tried really hard to make it worth making your boss pay for again. We'll see what the sales numbers are.
If you haven't seen it before, this book is meant to be accessible to managers, while still providing enough information to be useful to programmers, both lightweight VB types and heavyweight C++ types. The book is meant to be non-threatening, using a lot of pictures and diagrams, a small amount of simple VB code, and no C++ at all, which would scare off 80% of the potential readers. I write each chapter in a pyramidal structure, so managers can read the first three sections (Introduction, Problem Background, Solution Architecture). Ambitious managers and VB programmers can continue through the next section (Simplest Example). Heavier-duty developers can read the ends of the chapters, where I discuss more advanced elements of the topic. The book's Web site is, naturally, www.introducingmicrosoft.net. There you will find a free chapter on .NET My Services, as well as the code for all the book's samples, and a list of errata as soon as we find some. You'll also find a glowing review of the first edition here (well, what other kind did you expect me to link to? I may be crazy, but I'm not stupid.) written by Manohar Kamath. Here's the table of contents:
1. Introduction (updated to RTM) |
7. XML Serialization and Support (new chapter) |
2. .NET Objects (updated to RTM) |
8. Events and Delegates (new chapter) |
3. ASP.NET (updated to RTM) |
9. Threading (new chapter) |
4. .NET XML Web Services (updated to RTM, new material added, see this newsletter's feature article) | 10. Windows Forms Controls (new chapter) |
5. Windows Forms (updated to RTM, new material added) | 11. Web Forms Controls (new chapter) |
6. ADO.NET (updated to RTM, new material added, printed in book this time) | 12. Epilogue and Benediction (hasn't changed much) |
The second edition should be on shelves by May 10. You can pre-order it through amazon.com by following this link . It should be popular. The first edition was, and this one's better. On June 11, 2001, the first edition's sales rank on amazon.com was #762, thumping Tom Clancy's latest hardcover and paperback, hopelessly mired around #1400. That tells you something about Amazon's customers -- they're all geeks.
Internet Chuckle: Web Pages That Suck
How often have you looked at a Web site and said, "This REALLY sucks. How the hell can anyone put this on the web with a straight face?" Well, Vincent Flanders makes his living by holding these idiots up to public scorn and derision on his Web site http://www.webpagesthatsuck.com. I especially like his daily column, "What's New in Bad Design -- The Daily Sucker." It seems that there's no end to what people can dream up that just really, Really, REALLY sucks. He's arrogant and opinionated and calls 'em as he sees 'em -- sort of like me, come to think of it. For example, about the daily sucker for June 18, he wrote, "I don't give a left-handed flying farkle about how great you are. ... It took every ounce of self-restraint I had not to flip out over this site. This site is so full of marketing crap that I'm physically sick." Go to his site and you can see which one he was talking about. And the next time you find a sucky site that you think is worthy, send him a link. And if it wins, he'll post it on his site and send a message to the webmaster, saying something like, "Congratulations! Your site is the suckiest one I could find today on the entire Web! The large increase in hits you'll be getting in the next few days is people LAUGHING AT HOW BAD YOU ARE!" I love this idea, and I'd love to see the webmasters' faces when they get their prize announcements. One final note of caution -- anyone nominating this site will have their subscription revoked, even if I don't win.
I'm sorry to have to say it, but I haven't gotten enough reader interest to keep running this portion of the newsletter. The results of the last one are shown below. Thanks to everyone who submitted entries. Tell you what, I'll give you one more picture of my daughter to make up for it. One reader wrote, "Gosh, Dave, she's beautiful. She must look like her Mom."
Results of Last Contest: Jeopardy
First prize goes to Barry Doyle, who also won first prize for a geek greeting card a couple years ago. He joins Tana Sabatino as the only other person to win first prize twice.
A. Wile E. Coyote and Plattski's book
Q. What are two things with an anvil on them?
Second prize goes to Steve Crane
A. Zero
Q. How many letters are needed to write the name of one of the Internet's most
well known computer news sites.
He is of course referring to Slashdot, which can be written as /. using only punctuation marks.
Honorable mention to all the others from Barry Doyle:
A. WWW
Q. How does Cheney express disappointment in the president?
A. Microsoft
Q. What are two indications that you need Viagra?
A. IBM
Q. What is a simplistic way to indicate you are not constipated?
A. DCOM
Q. What comes before DStorm?
A. JCL code and giant femurs
Q. What are two things that come from dinosaurs?
A. .NET
Q. How did you catch .FISH?
A. IP Address
Q. What is the location of the rest room?
A. Programming
Q. How does Plattski refer to potty training his daughter?
Thunderclap is free, and is distributed via e-mail only. We never rent, sell or give away our mailing list. Subscription and unsubscription are handled by a human operator reading e-mail messages. To subscribe or unsubscribe, jump to the Rolling Thunder Web site and fill in the subscription form.
Legal Notices
Thunderclap does not accept advertising; nor do we sell, rent, or give away our subscriber list. We will make every effort to keep the names of subscribers private; however, if served with a court order, we will sing like a whole flock of canaries. If this bothers you, don't subscribe.
Source code and binaries supplied via this newsletter are provided "as-is", with no warranty of functionality, reliability or suitability for any purpose.
This newsletter is Copyright © 2001 by Rolling Thunder Computing, Inc., Ipswich MA. It may be freely redistributed provided that it is redistributed in its entirety, and that absolutely no changes are made in any way, including the removal of these legal notices.
Thunderclap is a registered trademark ® of Rolling Thunder Computing, Inc., Ipswich MA. All other trademarks are owned by their respective companies.