Tech Tutorials Database
GeekArticles XML Core XML
 

Understanding XForms: Components

 
Author: oreillynet.com
Category: Core XML
Comments (0)

I know, I know … when you talk about a series, it usually implies that the articles will be somewhat closer together than the ones for my Understanding XForms series has been. Mea culpa. The last couple of months have been busy, but a desire to wrap up my Firefox book (another mea culpa, if it comes to that) has combined with being fairly deeply immersed in the vagaries of XForms on Firefox to prompt me to write the third installment in this series. Take a look at the links at the end of the article for the previous installments. Please note in all of these that the assumption being made that the examples given here, if run in Mozilla Firefox, need the Xforms extension available at http://www.mozilla.org/projects/xforms/download.html. However, the examples should (in general) run in most contemporary XForms enabled browsers (a topic I’ll be discussing a couple of columns from now).

The Joy of XForms Components

Big complex data models look really imposing and impressive, but at the end of the day, XForms got their start largely because the existing HTML forms just weren’t expressive enough. Consider some of the more vexing problems associated with typical web forms. Suppose that you wished to:

  • choose a value from a given numeric range, rather than from a drop-down list?
  • create an invoice where you needed to add items to an invoice list?
  • enter a date in a consistent numerical format?
  • allow data into a text field that corresponded to a given regular expression pattern?
  • create tabbed panes of content?
  • create a wizard for gathering information?

All of these things can, of course, be done with the careful application of JavaScript, server side code, and perhaps third party plugins. The problem though is that most of these things are also fairly common operations in more traditional stand-alone applications, which has often spelled real trouble when such applications were then ported from the web. Moreover, there are no consistent standards from such solutions that seem to work universally on the web, especially from the standpoint of being able to tie such components into the bigger framework of web pages and CSS.

Thus, as the XForms working group within the W3C tried to grapple with making web components more application like, they also began to see the need to define more sophisticated structures for handling the use cases that arose in any number of business applications.

Consequently, one of the first things that came out of the working group was the realization that a component standard should be more concerned with interface requirements than it should be with presentation. In other words, XForms components needed to be abstract.

This notion is of course hardly foreign to HTML, but it is one that tends to be foreign to a lot of people who work regularly with web forms. The first pass of Web forms defined the notion of the field, with an associated type attribute that would determine whether it was an text box, a check box, a radio button, in short, everything that didn’t involve selecting from a list or dealing with multiline content.

There are several things wrong with this approach, things that only became obvious in retrospect. First of all, there are significant qualitative differences between a box of text and a checkbox - one can take potentially any string, the other can only hold one of four well defined state values (selected, unselected, disabled and indeterminate). This meant that the same statement needed to essentially be treated as perhaps half a dozen distinct elements, each with its own attributes, events properties and methods. This in turn made validation considerably more difficult, and became really hairy in the case of such things as radio buttons, which generally have no semantic meaning outside of groups).

Moreover, such components are fundamentally dumb. You can use script to handle manipulation of content, but its remarkable just how ugly such computations can be for even the simplest of operations. For instance,consider the following form fragment:

+

+

Not only do you have the fairly complex bit of manipulation when the “=” button is pressed just to add two numbers, but you are outputting to an input box, which means that a user could go in and change this field. Moreover, the “=” button has a largely spurious value - if this form was submitted this information would go with it even though it makes no different to the model.

Now compare this to the XForm way of doing things:

+ =

In this particular case, you are trading the complexity of DOM manipulation in Javascript for the complexity of creating a data model. Once that model is defined, however, you suddenly have components that are aware of one another through the data model - if you change the value in either field a or field b, not only does it change the data model, but that change then gets propagated back to a new element - the element, which can perform calculations upon the model itself. This may seem overkill here, but the value proves itself once you start getting into more complex situations (which I’ll cover in a bit).

The element is one of those which, once you start using it, you begin to wonder why it never ended up in the initial HTML set. It is a non-editable component that can either reflect the value of a given item in the data-model (via the ref attribute), or can reflect the result of a calculation (using XPath notation) via the value attribute.

Both the and methods can also be associated with a binding based on an element. For instance, in the above example, you could create a binding that performs the calculation and associates the result with another data member:

+ =

The output object (generally) only displays text content, though I’ll show some examples in the next column (customizing XForms) to demonstrate how to display other things, making the component considerably more useful.

One thing that you may notice if you are following along in this demonstration - when you type an entry into one of the input fields, nothing happens until you change the focus (by tabbing out or clicking outside of the control). This feature is built into XForms in order to insure that the proper processing can be handled in lower-capability devices. You can, however, change this behavior by including the attribute incremental=”true” on the input control in question. Once this happens, the component will force an update automatically whenever a change occurs. This becomes even more important when dealing with styling and customization issues.

One of the more frustrating elements missing from the set of core HTML tools is a simple slider, that lets you select between a range of numeric values. The component does precisely that. By specifying the start, end and an optional step value, you can create a slider that will let you select either a discrete or continuous value from that range (depending upon step). For instance, the following XHTML document uses two sliders to create a coordinate value (x,y) where both x and y can be expressed in 0.05 step intervals:

<style> .sliderValue {font-weight:bold;font-size:14pt;} </style> <xf:model> <xf:instance> <d:data a="0.0" b="0.0" c="(0,0)"/> </xf:instance> <xf:bind nodeset="/d:data/@c" calculate="concat('(',../@a,',',../@b,')')"/> </xf:model> </head> <body> <xf:range start="0" end="1" step="0.05" ref="@a"/>| <span class="sliderValue"> <xf:output ref="@a"/> </span><br/> <xf:range start="0" end="1" step="0.05" ref="@b"/>| <span class="sliderValue"> <xf:output ref="@b"/> </span><br/> <xf:output ref="@c"/> </body> </html> </p> <p>Most controls, including the <input> control, also have the ability to specify a few subtags, such as the <label> element. The label child will usually appear <em>before</em> the control itself, and will ignore any additional XHTML markup within the content of the label. The <hint> element will in turn provide a small pop-up whenever a user hovers over the control in question. Thus, in the previous example, the resulting coordinate could have been rendered as:</p> <p> <xf:output ref="@c"> <xf:label>Coordinate: </xf:label> <xf:hint>This is a coordinate somewhere within the unit square. </xf:hint> </xf:output> </p> <p>Note that unlike with straight XHTML, white space <em>is</em> preserved, so you should be very careful about this when designing your own xforms pages. This final form can be seen in Figure 1:</p> <img alt="images/sliders.jpg" src="http://www.oreillynet.com/xml/blog/images/sliders.jpg" target="_blank" rel="nofollow" width="377" height="171"/> <h5>Figure 1. XForm range controls</h5> <p>There are also two “specialty” input forms - the <secret> form, which is used for specifying password information in a way that you don’t want someone looking over your shoulder to see (and is the direct analog of the <input> type=”password”> HTML element), and the <upload> component, which lets you select a file from your current file system (either local or extended). The upload control tends to be fairly complex, as is illustrated below:</p> <p> <html xmlns="http://www.w3.org/1999/xhtml xmlns:xf="http://www.w3.org/2002/xforms" target="_blank" rel="nofollow" xmlns:ev="http://www.w3.org/2001/xml-events" target="_blank" rel="nofollow" xmlns:d="http://www.mydata.com/xmlns/data" target="_blank" rel="nofollow" xmlns:xs="http://www.w3.org/2001/XMLSchema" target="_blank" rel="nofollow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" target="_blank" rel="nofollow" xmlns:h="http://www.w3.org/1999/xhtml" target="_blank" rel="nofollow"> <head> <title/> <style> .sliderValue {font-weight:bold;font-size:14pt;} </style> <xf:model> <xf:instance> <d:files> <d:file filename="" mediatype="" size="" xsi:type="xs:anyURI"/> </d:files> </xf:instance> </xf:model> </head> <body> <xf:upload ref="/d:files/d:file[1]"> <xf:filename ref="@filename"/> <xf:mediatype ref="@mediatype"/> <xf:size ref="@size"/> </xf:upload> </body> </html> </p> <p>The <xf:filename> tag places the URI in question into the appropriate referenced item, with the selected media-type ending up in the mediatype element and size giving the size in bytes. At least in the Firefox implementation, I couldn’t get it to differentiate between different media types (it would always assume “*.*” as a file pattern), but otherwise brought up the appropriate file open dialog and populated the resulting field accordingly. (I have more to talk about on the submission side, but that will have to wait for THAT particular column as well … oh, man, am I committing myself here!)</p> <p>The one holdout to all of this text entry is the <textarea> element, which, not surprisingly, serves exactly the same purpose as the HTML version. At its simplest, it is useful for displaying blocks of plain text. However, because it is in fact an “abstract” control, you could in fact set additional properties, such as the appearance property in order to at least give the appearance that the component is a WYSIWYG component that generates HTML (or XHTML) in the background, something that will be illustrated in more detail when discussing customization. (It is of course well worth remembering that HTML and XHTML are both still “plain text”.) </p> <h4>Dealing with Selections</h4> <p>Few areas of forms are as frought with problems as the need to select one item (or more) from many. In HTML, most of the selection capability is scattered among four different types of controls - drop-down selection boxes, radio buttons, checkboxes and <select multiple=”multiple”< elements. </p> <p>One thing that the XForms working group recognized as they were developing the specification was the fact that there are fundamentally two distinct types of selection - the selection of a single item from a group, and the selection of multiple items from a group. Radio buttons and drop down select boxes represent this first viewpoint, checkboxes and multiple item select boxes represent the second. Given that there are potentially other forms of such controls, the idea emerged to just create two abstract components <select> and <select1> to handle the multiple and single version respectively, with the understanding that while the XForms engine would in fact implement <i>a</i> visual representation for each of these, the system should also make it possible to create alternative forms of the selection objects.</p> <p>Both the <select> and <select1> elements have similar forms, though their output is different. If you are working with a known set of items in the selection (such as colors in a list), you can use the <item> tag to provide the set of enumerations:</p> <p> <xf:model> <xf:instance id="dataStore"> <d:data color="#0000FF"/> </xf:instance> </xf:model> <xf:select1 ref="@color"> <xf:label>Colors</xf:label> <xf:item> <xf:label>Red</xf:label> <xf:value>#FF0000</xf:value> </xf:item> <xf:item> <xf:label>Green</xf:label> <xf:value>#00FF00</xf:value> </xf:item> <xf:item> <xf:label>Blue</xf:label> <xf:value>#0000FF</xf:value> </xf:item> </xf:select1> </p> <p>The <i>ref</i> attribute of course points to the data model, and should reflect the desired VALUE, rather than the label, of the given entry. For small entries (or entries that reflect an enumeration within a schema) this approach works quite well. On the other hand, there are occasionally times where it’s preferable to have the data populated from the model. In this case, you can use the <itemset> to pull information from the model:</p> <p> <xf:model> <xf:instance id="dataStore"> <d:data color="#0000FF"/> </xf:instance> <xf:instance id="colors"> <d:colors> <d:color name="Red" value="#FF0000"/> <d:color name="Green" value="#00FF00"/> <d:color name="Blue" value="#0000FF"/> <d:color name="Yellow" value="#FFFF00"/> <d:color name="Purple" value="#FF00FF"/> <d:color name="Cyan" value="#00FFFF"/> <d:color name="White" value="#FFFFFF"/> <d:color name="Black" value="#000000"/> </d:colors> </xf:instance> </xf:model> <xf:select1 ref="@color" id="dyncolors"> <xf:label>Colors</xf:label> <xf:itemset nodeset="instance('colors')/d:color"> <xf:label ref="@name"/> <xf:value ref="@value"/> </xf:itemset> </xf:select1> </p> <p>This illustrates a couple of concepts that I haven’t yet addressed in these columns. The first is the use of multiple instances within a given model.The first instance in this particular case contains information to be changed (it’ll likely be submitted to the server at some point). The second instance contains supporting information that may not be immediately germane to the immediate model of the first. This is useful for dealing with working with external data (such as would be enabled if the #colors instance had a src attribute instead of listing the items internally).</p> <p>You can use the instance() method in <i>ref</i> attributes to indicate an instance beyond the first (the XForms processor automatically uses first instance if no specific instance() is given. The instance() method will automatically point to the root node of the contained model - in this case the <colors> element in the #colors instance.</p> <p>You can also take advantage of using such models to create staggered selection boxes, where selecting one box will change the contents of another box. For instance, suppose that you wanted to display colors in a different languages, which were in turn given as another drop-down box. This might be illustrated as: </p> <p> <xf:model> <xf:instance id="dataStore"> <d:data color="#0000FF" lang="en" lang_color=""/> </xf:instance> <xf:instance id="lang_colors"> <d:colors> <d:colorset lang="en"> <d:color name="Red" value="#FF0000"/> <d:color name="Green" value="#00FF00"/> <d:color name="Blue" value="#0000FF"/> <d:color name="Yellow" value="#FFFF00"/> <d:color name="Purple" value="#FF00FF"/> <d:color name="Cyan" value="#00FFFF"/> <d:color name="White" value="#FFFFFF"/> <d:color name="Black" value="#000000"/> </d:colorset> <d:colorset lang="fr"> <d:color name="Rouge" value="#FF0000"/> <d:color name="Vert" value="#00FF00"/> <d:color name="Bleu" value="#0000FF"/> <d:color name="Jaune" value="#FFFF00"/> <d:color name="Pourpre" value="#FF00FF"/> <d:color name="Cyan" value="#00FFFF"/> <d:color name="Blanc" value="#FFFFFF"/> <d:color name="Noir" value="#000000"/> </d:colorset> <d:colorset lang="de"> <d:color name="Rotes" value="#FF0000"/> <d:color name="Grünes" value="#00FF00"/> <d:color name="Blaues" value="#0000FF"/> <d:color name="Gelbes" value="#FFFF00"/> <d:color name="Purpurrotes" value="#FF00FF"/> <d:color name="Cyan-blaues" value="#00FFFF"/> <d:color name="Weißes" value="#FFFFFF"/> <d:color name="Schwarzes" value="#000000"/> </d:colorset> </d:colors> </xf:instance> </xf:model> <xf:select1 ref="@lang" incremental="true"> <xf:label>Language: </xf:label> <xf:item> <xf:label>English</xf:label> <xf:value>en</xf:value> </xf:item> <xf:item> <xf:label>French</xf:label> <xf:value>fr</xf:value> </xf:item> <xf:item> <xf:label>German</xf:label> <xf:value>de</xf:value> </xf:item> </xf:select1> <xf:select1 ref="@lang_color"> <xf:label>Colors</xf:label> <xf:itemset nodeset="instance('lang_colors')/d:colorset[@lang = instance('dataStore')/@lang]/d:color"> <xf:label ref="@name"/> <xf:value ref="@value"/> </xf:itemset> </xf:select1> </p> <p>Within the model, the colors are now broken up by language, English, French and German. This in turn means that you have two levels of dependency - being able to choose the language, then from the language choosing the color. The second select1 statement: </p> <p> <xf:select1 ref="@lang_color"> <xf:label>Colors</xf:label> <xf:itemset nodeset="instance('lang_colors')/d:colorset[@lang = instance('dataStore')/@lang]/d:color"> <xf:label ref="@name"/> <xf:value ref="@value"/> </xf:itemset> </xf:select1> </p> <p>performs this task using a fairly complex XPath statement to retrieve the appropriate <colorset> object, based upon the the initial <i>lang</i> parameter in the first data-model instance.</p> <p>Now, the traditional web programmer here might be breaking into a bit of a sweat - the XPath expression there wasn’t exactly what I’d call intuitively obvious - but in point of fact this represents a significant advance in development. The single XPath expression has nicely summed up (as a business rule) the relationship between two disparate sets of data, and has done so in a way that doesn’t end up coupling the components themselves together - indeed, the second select1 box has absolutely no knowledge of the first (and vice versa) - it only knows about the data model. </p> <p>Things get a little more complex with the <select> element, though not by much. The value of a select box is a white-space separated string consisting of all of the values of the items selected in the list. In the default appearance mode, this sequence appears as a full list box, and typically by holding down the control (or command) key and selecting an unselected item, you will add that item to the selected set:</p> <p> <xf:select ref="d:colors"> <xf:label>Colors: </xf:label> <xf:itemset nodeset="instance('lang_colors')/d:colorset[@lang = instance('dataStore')/@lang]/d:color"> <xf:label ref="@name"/> <xf:value ref="@value"/> </xf:itemset> </xf:select> </p> <p>At least within the Firefox implementation, if you set the <i>appearance</i> attribute on the <select> tag to “full”, it does a <i>wonderful</i> thing - the control turns into collection of checkboxes with tags. (I suspect that the <select1> element will likely do the same as radio buttons, but at the time of writing this that functionality has not been implemented). What’s more, as with the select1 element, the checkboxes automatically reflect the state of the model, which means that constructing a preferences block becomes trivial - you keep a space separated list of indices that indicate which ones items are valid and the checkboxes will retain their state automatically.</p> <p>The following XHTML document showcases all of these features:</p> <p> <html xmlns="http://www.w3.org/1999/xhtml xmlns:h="http://www.w3.org/1999/xhtml" target="_blank" rel="nofollow" xmlns:s="http://www.w3.org/2000/svg xmlns:xlink="http://www.w3.org/1999/xlink" target="_blank" rel="nofollow" xmlns:d="http://www.w3.org/2005/Atom" target="_blank" rel="nofollow" xmlns:xf="http://www.w3.org/2002/xforms" target="_blank" rel="nofollow" xmlns:ev="http://www.w3.org/2001/xml-events" target="_blank" rel="nofollow"> <head> <title/> <style> @namespace xf url('http://www.w3.org/2002/xforms" target="_blank" rel="nofollow"'); select1 xf|itemset {width:60px;} </style> <xf:model> <xf:instance id="dataStore"> <d:data color="" lang="en" lang_color="> <d:colors/> </d:data> </xf:instance> <xf:instance id="colors"> <d:colors> <d:color name="Red" value="#FF0000"/> <d:color name="Green" value="#00FF00"/> <d:color name="Blue" value="#0000FF"/> <d:color name="Yellow" value="#FFFF00"/> <d:color name="Purple" value="#FF00FF"/> <d:color name="Cyan" value="#00FFFF"/> <d:color name="White" value="#FFFFFF"/> <d:color name="Black" value="#000000"/> </d:colors> </xf:instance> <xf:instance id="lang_colors"> <d:colors> <d:colorset lang="en"> <d:color name="Red" value="#FF0000"/> <d:color name="Green" value="#00FF00"/> <d:color name="Blue" value="#0000FF"/> <d:color name="Yellow" value="#FFFF00"/> <d:color name="Purple" value="#FF00FF"/> <d:color name="Cyan" value="#00FFFF"/> <d:color name="White" value="#FFFFFF"/> <d:color name="Black" value="#000000"/> </d:colorset> <d:colorset lang="fr"> <d:color name="Rouge" value="#FF0000"/> <d:color name="Vert" value="#00FF00"/> <d:color name="Bleu" value="#0000FF"/> <d:color name="Jaune" value="#FFFF00"/> <d:color name="Pourpre" value="#FF00FF"/> <d:color name="Cyan" value="#00FFFF"/> <d:color name="Blanc" value="#FFFFFF"/> <d:color name="Noir" value="#000000"/> </d:colorset> <d:colorset lang="de"> <d:color name="Rotes" value="#FF0000"/> <d:color name="Grünes" value="#00FF00"/> <d:color name="Blaues" value="#0000FF"/> <d:color name="Gelbes" value="#FFFF00"/> <d:color name="Purpurrotes" value="#FF00FF"/> <d:color name="Cyan-blaues" value="#00FFFF"/> <d:color name="Weißes" value="#FFFFFF"/> <d:color name="Schwarzes" value="#000000"/> </d:colorset> </d:colors> </xf:instance> </xf:model> </head> <body> <h4>Select1 Static Colors</h4> <xf:select1 ref="@color"> <xf:label>Colors</xf:label> <xf:item> <xf:label>Red</xf:label> <xf:value>#FF0000</xf:value> </xf:item> <xf:item> <xf:label>Green</xf:label> <xf:value>#00FF00</xf:value> </xf:item> <xf:item> <xf:label>Blue</xf:label> <xf:value>#0000FF</xf:value> </xf:item> </xf:select1> <h4>Select1 Dynamic Colors</h4> <xf:select1 ref="@color" id="dyncolors"> <xf:label>Colors</xf:label> <xf:itemset nodeset="instance('colors')/d:color"> <xf:label ref="@name"/> <xf:value ref="@value"/> </xf:itemset> </xf:select1> <h4>Staggered Select1 Boxes</h4> <xf:select1 ref="@lang" incremental="true"> <xf:label>Language: </xf:label> <xf:item> <xf:label>English</xf:label> <xf:value>en</xf:value> </xf:item> <xf:item> <xf:label>French</xf:label> <xf:value>fr</xf:value> </xf:item> <xf:item> <xf:label>German</xf:label> <xf:value>de</xf:value> </xf:item> </xf:select1> <xf:select1 ref="@lang_color"> <xf:label>Colors</xf:label> <xf:itemset nodeset="instance('lang_colors')/d:colorset[ @lang = instance('dataStore')/@lang]/d:color"> <xf:label ref="@name"/> <xf:value ref="@value"/> </xf:itemset> </xf:select1> <xf:output ref="@lang_color"/> <h4>Select Boxes</h4> <xf:select ref="d:colors"> <xf:label>Colors: </xf:label> <xf:itemset nodeset="instance('lang_colors')/d:colorset[ @lang = instance('dataStore')/@lang]/d:color"> <xf:label ref="@name"/> <xf:value ref="@value"/> </xf:itemset> </xf:select> <xf:select ref="d:colors" appearance="full"> <xf:label>Colors: </xf:label> <xf:itemset nodeset="instance('lang_colors')/d:colorset[ @lang = instance('dataStore')/@lang]/d:color"> <xf:label ref="@name"/> <xf:value ref="@value"/> </xf:itemset> </xf:select> <xf:output ref="d:colors"/> </body> </html> </p> <p>You can see all of these as a screenshot in Figure 2.</p> <img src="http://www.oreillynet.com/xml/blog/images/SelectAndSelect1.jpg" target="_blank" rel="nofollow"/> <h5>Figure 2. Select and Select1 controls</h5> <h4>Grouping and Repeating</h4> <p>One of the more significant things that XForms introduces into a web page is the notion of context. If you’re familiar with XPath or XSLT, context should be clear, but for those that are coming to XForms from a different direction, context can be thought of as the place within an XML document where all XPath operations are based. </p> <p>You can see the context at work in the <itemset> element: the nodeset identifies the elements that will provide the data (in this case all XML nodes retrieved at <i>instance(’lang_colors’)/d:colorset[@lang = instance(’dataStore’)/@lang]/d:color</i>, while the label and value assume each of these nodes as a current content and provide the XPath only relative to those elements.</p> <p>The <group> element serves a number of functions, but perhaps its most important is to change the context of everything within it. Taking a <i>ref</i> attribute, the group serves to anchor a given context so that anything within it is given <i>relative</i> to the group. For instance, suppose that you start with a model giving a person’s name and address, you could either give this information using absolute XPath expressions (which include a lot of redundancy) or you could use the power of groups to better organize the content:</p> <p> <html xmlns="http://www.w3.org/1999/xhtml xmlns:h="http://www.w3.org/1999/xhtml" target="_blank" rel="nofollow" xmlns:s="http://www.w3.org/2000/svg xmlns:xlink="http://www.w3.org/1999/xlink" target="_blank" rel="nofollow" xmlns:d="http://www.w3.org/2005/Atom xmlns:xf="http://www.w3.org/2002/xforms" target="_blank" rel="nofollow" xmlns:ev="http://www.w3.org/2001/xml-events" target="_blank" rel="nofollow"> <head> <title/> <xf:model> <xf:instance id="dataStore"> <d:records> <d:record> <d:id>kcagle</d:id> <d:identity> <d:firstname>Kurt</d:firstname> <d:middleinitial>A</d:middleinitial> <d:surname>Cagle</d:surname> <d:gender>Male</d:gender> <d:dataofbirth>1962-02-21</d:dataofbirth> </d:identity> <d:address> <d:street>1313 Mockingbird Lane</d:street> <d:city>Victoria</d:city> <d:region>British Columbia</d:region> <d:country>Canada</d:country> </d:address> </d:record> <d:record> <d:id>adelamare</d:id> <d:identity> <d:firstname>Aleria</d:firstname> <d:middleinitial>B</d:middleinitial> <d:surname>Delamare</d:surname> <d:gender>Female</d:gender> <d:dataofbirth>1981-11-06</d:dataofbirth> </d:identity> <d:address> <d:street>123 Sesame Street</d:street> <d:city>New York</d:city> <d:region>New York</d:region> <d:country>United States</d:country> </d:address> </d:record> </d:records> </xf:instance> </xf:model> </head> <body> <h2>Without Grouping</h2> <h4>User Information</h4> <xf:input ref="d:record[d:id = 'kcagle']/d:identity/d:firstname"> <xf:label>First Name: </xf:label> </xf:input> <xf:input ref="d:record[d:id = 'kcagle']/d:identity/d:middleinitial"> <xf:label>Middle Initial: </xf:label> </xf:input> <xf:input ref="d:record[d:id = 'kcagle']/d:identity/d:surname"> <xf:label>Surname: </xf:label> </xf:input> <h4>Address</h4> <xf:input ref="d:record[d:id = 'kcagle']/d:address/d:street"> <xf:label>Street: </xf:label> </xf:input> <xf:input ref="d:record[d:id = 'kcagle']/d:address/d:city"> <xf:label>City: </xf:label> </xf:input> <xf:input ref="d:record[d:id = 'kcagle']/d:address/d:region"> <xf:label>Region: </xf:label> </xf:input> <xf:input ref="d:record[d:id = 'kcagle']/d:address/d:country"> <xf:label>Country: </xf:label> </xf:input> <h2>With Grouping</h2> <h4>User Information</h4> <xf:group ref="d:record[d:id = 'kcagle']"> <xf:group ref="d:identity"> <xf:input ref="d:firstname"> <xf:label>First Name: </xf:label> </xf:input> <xf:input ref="d:middleinitial"> <xf:label>Middle Initial: </xf:label> </xf:input> <xf:input ref="d:surname"> <xf:label>Surname: </xf:label> </xf:input> </xf:group> <xf:group ref="d:address"> <h4>Address</h4> <xf:input ref="d:street"> <xf:label>Street: </xf:label> </xf:input> <xf:input ref="d:city"> <xf:label>City: </xf:label> </xf:input> <xf:input ref="d:region"> <xf:label>Region: </xf:label> </xf:input> <xf:input ref="d:country"> <xf:label>Country: </xf:label> </xf:input> </xf:group> </xf:group> </body> </html> </p> <p>What’s more, by working with such groups, you are better able to leverage XPath for controlling content display while at the same time keeping internal structure the same. For instance, you could actually have a controller that will show different records using a select1 control (illustrated in Figure 3):</p> <p> <html xmlns="http://www.w3.org/1999/xhtml xmlns:h="http://www.w3.org/1999/xhtml" target="_blank" rel="nofollow" xmlns:s="http://www.w3.org/2000/svg xmlns:xlink="http://www.w3.org/1999/xlink" target="_blank" rel="nofollow" xmlns:d="http://www.w3.org/2005/Atom xmlns:xf="http://www.w3.org/2002/xforms" target="_blank" rel="nofollow" xmlns:ev="http://www.w3.org/2001/xml-events" target="_blank" rel="nofollow"> <head> <title/> <xf:model> <xf:instance id="currentRecord"> <d:data id="kcagle"/> </xf:instance> <xf:instance id="dataStore"> <d:records> <d:record> <d:id>kcagle</d:id> <d:identity> <d:firstname>Kurt</d:firstname> <d:middleinitial>A</d:middleinitial> <d:surname>Cagle</d:surname> <d:gender>Male</d:gender> <d:dataofbirth>1962-02-21</d:dataofbirth> </d:identity> <d:address> <d:street>1313 Mockingbird Lane</d:street> <d:city>Victoria</d:city> <d:region>British Columbia</d:region> <d:country>Canada</d:country> </d:address> </d:record> <d:record> <d:id>adelamare</d:id> <d:identity> <d:firstname>Aleria</d:firstname> <d:middleinitial>B</d:middleinitial> <d:surname>Delamare</d:surname> <d:gender>Female</d:gender> <d:dataofbirth>1981-11-06</d:dataofbirth> </d:identity> <d:address> <d:street>123 Sesame Street</d:street> <d:city>New York</d:city> <d:region>New York</d:region> <d:country>United States</d:country> </d:address> </d:record> </d:records> </xf:instance> </xf:model> <style> @namespace xf url('http://www.w3.org/2002/xforms" target="_blank" rel="nofollow"'); xf|select1 xf|itemset {width:120px;} </style> </head> <body> <xf:select1 ref="@id"> <xf:itemset nodeset="instance('dataStore')/d:record"> <xf:label ref="d:id"/> <xf:value ref="d:id"/> </xf:itemset> </xf:select1> <xf:output ref="@id)"/> <xf:group ref="instance('dataStore')/d:record[string(d:id) = string(instance('currentRecord')/@id)]"> <xf:group ref="d:identity"> <h4>User Information for <xf:output value="concat(d:firstname,' ',d:surname)"/></h4> <xf:input ref="d:firstname"> <xf:label>First Name: </xf:label> </xf:input> <xf:input ref="d:middleinitial"> <xf:label>Middle Initial: </xf:label> </xf:input> <xf:input ref="d:surname"> <xf:label>Surname: </xf:label> </xf:input> </xf:group> <xf:group ref="d:address"> <h4>Address</h4> <xf:input ref="d:street"> <xf:label>Street: </xf:label> </xf:input> <xf:input ref="d:city"> <xf:label>City: </xf:label> </xf:input> <xf:input ref="d:region"> <xf:label>Region: </xf:label> </xf:input> <xf:input ref="d:country"> <xf:label>Country: </xf:label> </xf:input> </xf:group> </xf:group> </body> </html> </p> <img src="http://www.oreillynet.com/xml/blog/images/group.jpg" target="_blank" rel="nofollow"/> <h5>Figure 3. Use of the group control.</h5> <p>In this particular case powerfully illustrates the concept of grouping - the local information contained within the displayed record remains the same, but by switching contexts via the select1 object, you have the ability to migrate through multiple records effortlessly. Now, in this case the assumption is made that ALL of these records are locally available, making this at best an impractical situation for large databases, but the goal here is more to illustrate how groups can be used to create context switches. </p> <p>The notion of context also plays a significant role in another XForms-only feature, the ability to repeat through all items that share a given context specification. For instance, in the previous example, the specific nodeset “d:record” points not to one record but to all records in the collection. By using the <xf:repeat> element, it is possible to iterate through all of the records and display them. For instance, the following will repeat the input fields for <i>all</i> of the record nodes from the previous example, as shown in Figure 4.</p> <p> <html xmlns="http://www.w3.org/1999/xhtml xmlns:h="http://www.w3.org/1999/xhtml" target="_blank" rel="nofollow" xmlns:d="http://www.w3.org/2005/Atom xmlns:xf="http://www.w3.org/2002/xforms" target="_blank" rel="nofollow"> <head> <title/> <xf:model> <xf:instance id="currentRecord"> <d:data id="kcagle"/> </xf:instance> <xf:instance id="dataStore"> <d:records> <d:record> <d:id>kcagle</d:id> <d:identity> <d:firstname>Kurt</d:firstname> <d:middleinitial>A</d:middleinitial> <d:surname>Cagle</d:surname> <d:gender>Male</d:gender> <d:dataofbirth>1962-02-21</d:dataofbirth> </d:identity> <d:address> <d:street>1313 Mockingbird Lane</d:street> <d:city>Victoria</d:city> <d:region>British Columbia</d:region> <d:country>Canada</d:country> </d:address> </d:record> <d:record> <d:id>adelamare</d:id> <d:identity> <d:firstname>Aleria</d:firstname> <d:middleinitial>B</d:middleinitial> <d:surname>Delamare</d:surname> <d:gender>Female</d:gender> <d:dataofbirth>1981-11-06</d:dataofbirth> </d:identity> <d:address> <d:street>123 Sesame Street</d:street> <d:city>New York</d:city> <d:region>New York</d:region> <d:country>United States</d:country> </d:address> </d:record> <d:record> <d:id>tdimeon</d:id> <d:identity> <d:firstname>Theodore</d:firstname> <d:middleinitial>A</d:middleinitial> <d:surname>Dimeon</d:surname> <d:gender>Male</d:gender> <d:dataofbirth>1972-05-11</d:dataofbirth> </d:identity> <d:address> <d:street>31416 Pi St.</d:street> <d:city>Olympia</d:city> <d:region>Washington</d:region> <d:country>United States</d:country> </d:address> </d:record> </d:records> </xf:instance> </xf:model> <style> @namespace xf url('http://www.w3.org/2002/xforms" target="_blank" rel="nofollow"'); xf|select1 xf|itemset {width:120px;} </style> </head> <body> <xf:repeat nodeset="instance('dataStore')/d:record"> <fieldset> <legend><xf:output value="concat(d:identity/d:surname, ', ',d:identity/d:firstname)"/></legend> <xf:repeat nodeset="d:identity"> <h4>Identity</h4> <xf:input ref="d:firstname"> <xf:label>First Name: </xf:label> </xf:input> <xf:input ref="d:middleinitial"> <xf:label>Middle Initial: </xf:label> </xf:input> <xf:input ref="d:surname"> <xf:label>Surname: </xf:label> </xf:input> </xf:repeat> <xf:repeat nodeset="d:address"> <h4>Address</h4> <xf:input ref="d:street"> <xf:label>Street: </xf:label> </xf:input> <xf:input ref="d:city"> <xf:label>City: </xf:label> </xf:input> <xf:input ref="d:region"> <xf:label>Region: </xf:label> </xf:input> <xf:input ref="d:country"> <xf:label>Country: </xf:label> </xf:input> </xf:repeat> </fieldset> </xf:repeat> </body> </html> </p> <img src="http://www.oreillynet.com/xml/blog/images/repeat.jpg" target="_blank" rel="nofollow"/> <h5>Figure 4. Use of the repeat control.</h5> <p>If there is only one node, then the repeat tag acts much like a group tag. In the current Firefox implementation of XForms, there are some odd interactions between group and repeat elements that occasionally can make for some unpredictable behavior. In this case, you can substitute repeat for group without much difference, save that a <repeat> element takes a <i>nodeset</i> attribute, while a <group> element takes a <i>ref</i> attribute.</p> <h4>Summary</h4> <p>While this does not represent the <i>whole</i> spectrum of components, it covers those that can operate without needing to understanding the eventing model currently used by XForms, so this seems a good point to break. In the next column on XForms I will cover the use of CSS and XBL Bindings to change the behavior of XForms, and in the final column will look at the XForms event model and how it makes possible such things as wizards and multipage forms.</p> <h4>Links to previous articles in this series:</h4> <p><a href="http://www.oreillynet.com/xml/blog/2006/03/why_xforms_matter_revisited.html" target="_blank" rel="nofollow">Why XForms Matter Revisited</a></p> <p><a href="http://www.oreillynet.com/xml/blog/2006/03/understanding_xforms_the_model.html" target="_blank" rel="nofollow">Understanding XForms: The Model</a></p> <hr/> <p><i><a href="mailto:kurt.cagle@gmail.com">Kurt Cagle</a> is an author and computer consultant specializing in AJAX and Web 2.0 technologies. He lives in Victoria, British Columbia, and is slowly learning how to say ‘eh’.</i></p> <script type="text/javascript" language="JavaScript">var site="s12metaphoricalweb"</script> <script type="text/javascript" language="JavaScript1.2" src="http://s12.sitemeter.com/js/counter.js?site=s12metaphoricalweb"></script> <noscript> <a href="http://s12.sitemeter.com/stats.asp?site=s12metaphoricalweb target="_top"> <img src="http://s12.sitemeter.com/meter.asp?site=s12metaphoricalweb" alt="Site Meter" border="0"/></a> </noscript><p style='text-align:right;'><a target='_blank' href='http://www.geekarticles.com/visit/Understanding-XForms-Components.html'><b>Read More...</b></a></p><hr><div><div style="clear:both;"></div> <p><!-- --> <div style="float:center;"> <script type="text/javascript"> <!-- microsoft_adunitid="1600"; microsoft_adunit_width="300"; microsoft_adunit_height="250"; microsoft_adunit_legacy="true";//--> </script> <script type="text/javascript" src="http://adsyndication.msn.com/delivery/getads.js" ></script> </div></p><div style="clear:both;"></div> </div><br/><div width=45% style='clear:both; float:right;'><b>Read Next:</b> <a href='http://www.geekarticles.com/article/Ruminations-on-Turning-43.html'><b>Ruminations on Turning 43</b></a></div><br /><br /><br><div class='spacer'> </div><div id='widepanel' style='border-top-style:solid; border-top-width:1px;'><div id='quarterh'>Related Topics</div><div class='panel_wide_column'><a href='http://www.geekarticles.com/article/Components-and-Aspects-of-Our-Personality.html'>Components and Aspects of Our Personality</a></div><div class='panel_wide_column'><a href='http://www.geekarticles.com/article/Understanding-Delphi-SET-Types-1.html'>Understanding Delphi SET Types</a></div><div class='panel_wide_column'><a href='http://www.geekarticles.com/article/Understanding-the-Java-Portlet-Specification-20-JSR-286.html'>Understanding the Java Portlet Specification 2.0 (JSR 286)</a></div><div class='panel_wide_column'><a href='http://www.geekarticles.com/article/GLibWMI-Components-Library.html'>GLibWMI Components Library</a></div><div class='panel_wide_column'><a href='http://www.geekarticles.com/article/Article-Understanding-HTML-and-XHTML-Connections-.html'>Article :: Understanding HTML and XHTML Connections</a></div><br> <form action='/search.html' method='post'> <div> <input type='text' name='t' size='31' /> <input type='submit' name='sa' value='Search' /> </div> </form> </div><br> <br><div style='clear: both;'><h3>Comments</h3><br> <style> .CommentTitle { margin-bottom: 6px; font-size: 1em; font-weight: normal; color: black; } .CommentArea { margin-top: 8px; margin-right: 4px; margin-bottom: 8px; margin-left: 0px; width: 99%; display: block; font-family: Georgia,sans-serif,Tahoma,Verdana,Geneva,Arial,Verdana,Geneva,Arial,Helvetica,sans-serif; font-size: 13px; color: black; } .CommentArea td div p { font-family: Georgia,sans-serif,Tahoma,Verdana,Geneva,Arial,Verdana,Geneva,Arial,Helvetica,sans-serif; font-size: 13px; color: black; } .CommentArrow { background-image: url(/images/comment-arrow.gif); background-repeat: no-repeat; width: 14px; height: 14px; margin-bottom: -14px; } .CommentFooter { margin-top: 4px; font-size: 80%; color: #666666; padding-left: 16px; } .CommentText blockquote { color: #747474; padding-left: 30px; } .CommentText2 { border: solid 1px #bcbcbc; padding: 3px; } .CommentText3{ padding: 5px; font-size: .9em; } .CommentText{ padding-bottom: 3px; background-image: url(/images/comment-shadow.gif); background-repeat: repeat-x; background-position: left bottom; } </style><br /><div style='clear: both;'><a id='art_cmts'></a><script type='text/javascript' src='http://www.geekarticles.com/jscripts/md5.js'></script> <script type='text/javascript'> function V2(cmtForm) { if (Validate1_cmtForm(cmtForm) == false) return false; if (Validate2_cmtForm(cmtForm) == false) return false; } function V3(cmtForm,x) { if (Validate1_cmtForm(cmtForm) == false) return false; if (Validate2_cmtForm(cmtForm) == false) return false; if (Validate3_cmtForm(cmtForm,x) == false) return false; } function Validate1_cmtForm(cmtForm) { cmtForm.cmt.value = trim(cmtForm.cmt.value); if (cmtForm.cmt.value == '') { alert('Please enter your comment.') cmtForm.cmt.focus(); return (false); } if (cmtForm.cmt.value.toUpperCase() == cmtForm.cmt.value) { alert('Sorry, Full UPPERCASE comments are not allowed.') cmtForm.cmt.focus(); return (false); } } function Validate2_cmtForm(cmtForm) { cmtForm.uname.value = trim(cmtForm.uname.value); cmtForm.uemail.value = trim(cmtForm.uemail.value); if (cmtForm.uname.value == '') { alert('Please enter your name.') cmtForm.uname.focus(); return (false); } if (cmtForm.uemail.value == '') { alert('Please enter your e-mail id.'); cmtForm.uemail.focus(); return (false); } var checkEmail = '@.'; var checkStr = cmtForm.uemail.value; var EmailValid = false; var EmailAt = false; var EmailPeriod = false; for (i = 0; i < checkStr.length; i++) { ch = checkStr.charAt(i); for (j = 0; j < checkEmail.length; j++) { if (ch == checkEmail.charAt(j) && ch == '@') EmailAt = true; if (ch == checkEmail.charAt(j) && ch == '.') EmailPeriod = true; if (EmailAt && EmailPeriod) break; if (j == checkEmail.length) break; } if (EmailAt && EmailPeriod) { EmailValid = true break; } } if (!EmailValid) { alert('Invalid e-mail ID'); cmtForm.uemail.focus(); return (false); } } function Validate3_cmtForm(cmtFor,x) { if (x==1 && cmtForm.imgcode.value == '') { alert('Please enter image verification code.') cmtForm.imgcode.focus(); return (false); } var xmlHttp; try { xmlHttp=new XMLHttpRequest(); } catch (e) { try { xmlHttp=new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { try { xmlHttp=new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) { alert('Your browser does not support AJAX!'); return false; } } } xmlHttp.onreadystatechange=function() { if (xmlHttp.readyState==4 || xmlHttp.readyState=='complete') { cmtForm.vimgcode.value=xmlHttp.responseText; if (trim(cmtForm.vimgcode.value)=='') { cmtForm.vimgcode.value=xmlHttp.responseObject; } } } xmlHttp.open('GET','http://www.geekarticles.com/lib/randmimgno.php',true,'',''); xmlHttp.send(null); if (cmtForm.imgcode.value != cmtForm.vimgcode.value) { alert('Invalid Verification Code.'); cmtForm.imgcode.focus(); return (false); } } function trim(str, chars) { return ltrim(rtrim(str, ' '), ' '); } function ltrim(str, chars) { chars = chars || '\s'; return str.replace(new RegExp('^[' + chars + ']+', 'g'), ''); } function rtrim(str, chars) { chars = chars || '\s'; return str.replace(new RegExp('[' + chars + ']+$', 'g'), ''); } </script> <style type='text/css'> <!-- .head4 { margin: 0; padding: 0; color:#336699;} .inputfld { border-style: solid; border-width: 1px; border-color: silver; margin-top:5px; } .txtarea { border-style: solid; border-width: 1px; border-color: silver; margin-top:5px; } #cmtbox { border: dotted; border-width: 1px; padding: 10px; font-family: Verdana, Tahoma, Arial, Helvetica, sans-serif; font-size: 12px; width: 565px; max-width: 565px; border-color: silver; background-color:#f6f6f6; height:240px; margin-left:auto; margin-right:auto; } #cmtbox2 { border: dotted; border-width: 1px; padding: 10px; font-family: Verdana, Tahoma, Arial, Helvetica, sans-serif; font-size: 12px; width: 565px; max-width: 565px; border-color: silver; background-color:#f6f6f6; height:175px; margin-left:auto; margin-right:auto; } --> </style> <div id='cmtbox'> <form style='margin:0;' name='cmtForm' onsubmit='return V3(this,1);' method='POST' action='/article/Understanding-XForms-Components.html'> <h4 class='head4'>Post Your Comment:</h4> <input type='hidden' name='artid' value='18640' /> <input type='hidden' name='arturl' value='/article/Understanding-XForms-Components.html' /> <input type='hidden' name='pid' value='0' /> <input type='hidden' name='tk' value='1' /> <input type='hidden' name='userid' value='' /> <input type='hidden' name='username' value='' /> <textarea name='cmt' class='txtarea' cols='67' rows='7'></textarea> <div style='margin-top:5px; margin-right:5px; float:left; width:246px; '>Your Name:<font color='red'>*</font><br> <input name='uname' size='37' class='inputfld' onblur='verifyname()'></div> <div style='margin-top:5px; float:left; margin-left:5px; width:250px; text-align: left;'>e-mail ID:<font size='1'>(required for notification)</font><font color='red'>*</font><br> <input name='uemail' size='46' class='inputfld'></div> <div style='clear:both; width:422px;'> <div style='float:left; width:125px; padding-top:9px;'>Image Verification: </div> <div style='float:left; width:60px;'><img border=0 src='http://www.geekarticles.com/lib/randmimgn.php'>  <input type='hidden' name='vimgcode' id='vimgcode'></div> <div style='float:left; margin-left:5px; width:60px; text-align:left; padding-top:3px;'><input name='imgcode' id='imgcode' size='5' class='inputfld' onfocus='return Validate3_cmtForm(cmtForm,0);' maxlength='5'></div> <div style='float:right; width:170px; text-align:right; padding-top:5px;'> <input name='mode' size='0' type='hidden' value='send'> <input type='checkbox' name='cmtnotify' value=1> Subscribe     <input type='submit' value='Submit'></div> </div> </form> </div> <br /></div></div> </div> </div> <div class="right_panel"> <h3>Subscribe via RSS</h3><div style="min-height: 170px; margin:10px 0 0 0; padding: 0; border:1px solid #ccc;"> <p style='margin:15px 0 0 0; padding:0; text-align:center;'><a href="http://feedburner.google.com/fb/a/mailverify?uri=geekarticles&loc=en_US">Subscribe to GeekArticles.com by Email</a></p> <p style='margin:5px 0 0 0; padding:0; text-align:center;'><a href="http://feedproxy.google.com/geekarticles"><img src="http://feedproxy.google.com/~fc/geekarticles?bg=99CCFF&fg=444444&anim=0" height="26" width="88" style="border:0" alt="" /></a></p> <p style='margin:15px 0 0 0; padding:0; text-align:center;><a href="http://feeds.feedburner.com/geekarticles"><img src="http://feeds.feedburner.com/~fc/geekarticles?bg=99CCFF&fg=444444&anim=0" height="26" width="88" style="border:0" alt="" /></a></p> <form style="margin:0; border:0px; padding:3px; text-align:center;" action="http://feedburner.google.com/fb/a/mailverify" method="post" target="popupwindow" onsubmit="window.open('http://feedburner.google.com/fb/a/mailverify?uri=geekarticles', 'popupwindow', 'scrollbars=yes,width=550,height=520');return true"> <p style='margin:10px 0 0 0; padding:0; text-align:center;'>Enter your email address:</p> <p style='margin:10px 0 0 0; padding:0; text-align:center;'><input type="text" style="border-style: solid; border-width: 1px; margin: 0px 5px 0 5px; padding: 3px; width:140px" name="email"/><input type="hidden" value="geekarticles" name="uri"/><input type="hidden" name="loc" value="en_US"/></p> <p style='margin:10px 0 0 0; padding:0; text-align:center;'><input type="submit" value="Subscribe" class="button" /></p></form> <p style='margin:15px 0 0 0; padding:0; text-align:center;'><a href="http://feeds.feedburner.com/geekarticles" title="Subscribe to my feed" rel="alternate" type="application/rss+xml"><img src="http://www.feedburner.com/fb/images/pub/feed-icon32x32.png" alt="" style="border:0"/></a> <a href="http://feeds.feedburner.com/geekarticles" title="Subscribe to my feed" rel="alternate" type="application/rss+xml">Subscribe in a reader</a></p><br><br> </div> <div class='spacer_big'> </div><h3>Core XML</h3><div class='right_articles'><div class='panel_wide_column'> <div id='panel_item'><ul style='display: block; margin:0; padding:0; margin-left:15px;'> <li class='homelist'><a href='http://www.geekarticles.com/article/XML-Schema-Design-Patterns-Is-Complex-Type-Derivation-Unnecessar.html'>XML Schema Design Patterns: Is Complex Type Derivation Unnecessary?</a></li></ul></div></div><div class='panel_wide_column'> <div id='panel_item'><ul style='display: block; margin:0; padding:0; margin-left:15px;'> <li class='homelist'><a href='http://www.geekarticles.com/article/XML-Ain-t-What-It-Used-To-Be.html'>XML Ain't What It Used To Be</a></li></ul></div></div><div class='panel_wide_column'> <div id='panel_item'><ul style='display: block; margin:0; padding:0; margin-left:15px;'> <li class='homelist'><a href='http://www.geekarticles.com/article/Using-XML-Catalogs-with-JAXP.html'>Using XML Catalogs with JAXP</a></li></ul></div></div><div class='panel_wide_column'> <div id='panel_item'><ul style='display: block; margin:0; padding:0; margin-left:15px;'> <li class='homelist'><a href='http://www.geekarticles.com/article/XML-on-the-Move.html'>XML on the Move</a></li></ul></div></div><div class='panel_wide_column'> <div id='panel_item'><ul style='display: block; margin:0; padding:0; margin-left:15px;'> <li class='homelist'><a href='http://www.geekarticles.com/article/XML-2000-Coverage.html'>XML 2000 Coverage</a></li></ul></div></div><div class='panel_wide_column'> <div id='panel_item'><ul style='display: block; margin:0; padding:0; margin-left:15px;'> <li class='homelist'><a href='http://www.geekarticles.com/article/Making-XML-Work-in-Business.html'>Making XML Work in Business</a></li></ul></div></div><div class='panel_wide_column'> <div id='panel_item'><ul style='display: block; margin:0; padding:0; margin-left:15px;'> <li class='homelist'><a href='http://www.geekarticles.com/article/XML-Source-Highlighting.html'>XML Source Highlighting</a></li></ul></div></div><div class='panel_wide_column'> <div id='panel_item'><ul style='display: block; margin:0; padding:0; margin-left:15px;'> <li class='homelist'><a href='http://www.geekarticles.com/article/Using-XML-for-Web-Publishing.html'>Using XML for Web Publishing</a></li></ul></div></div><div class='panel_wide_column'> <div id='panel_item'><ul style='display: block; margin:0; padding:0; margin-left:15px;'> <li class='homelist'><a href='http://www.geekarticles.com/article/What-is-XM.html'>What is XML?</a></li></ul></div></div><div class='panel_wide_column'> <div id='panel_item'><ul style='display: block; margin:0; padding:0; margin-left:15px;'> <li class='homelist'><a href='http://www.geekarticles.com/article/Binary-XML-Again.html'>Binary XML, Again</a></li></ul></div></div><div class='panel_wide_column'> <div id='panel_item'><ul style='display: block; margin:0; padding:0; margin-left:15px;'> <li class='homelist'><a href='http://www.geekarticles.com/article/Does-XML-Query-Reinvent-the-Whee.html'>Does XML Query Reinvent the Wheel?</a></li></ul></div></div><div class='panel_wide_column'> <div id='panel_item'><ul style='display: block; margin:0; padding:0; margin-left:15px;'> <li class='homelist'><a href='http://www.geekarticles.com/article/XML-Technologies-A-Success-Story.html'>XML Technologies: A Success Story</a></li></ul></div></div><div class='panel_wide_column'> <div id='panel_item'><ul style='display: block; margin:0; padding:0; margin-left:15px;'> <li class='homelist'><a href='http://www.geekarticles.com/article/Web-based-XML-Editing-with-W3C-XML-Schema-and-XSLT.html'>Web-based XML Editing with W3C XML Schema and XSLT</a></li></ul></div></div><div class='panel_wide_column'> <div id='panel_item'><ul style='display: block; margin:0; padding:0; margin-left:15px;'> <li class='homelist'><a href='http://www.geekarticles.com/article/XML-Hype-Down-But-Not-Out-In-New-York.html'>XML Hype Down But Not Out In New York</a></li></ul></div></div><div class='panel_wide_column'> <div id='panel_item'><ul style='display: block; margin:0; padding:0; margin-left:15px;'> <li class='homelist'><a href='http://www.geekarticles.com/article/Berkeley-DB-XML-An-Embedded-XML-Database.html'>Berkeley DB XML: An Embedded XML Database</a></li></ul></div></div><div class='panel_wide_column'> <div id='panel_item'><ul style='display: block; margin:0; padding:0; margin-left:15px;'> <li class='homelist'><a href='http://www.geekarticles.com/article/Evaluating-XML-Editors.html'>Evaluating XML Editors</a></li></ul></div></div><div class='panel_wide_column'> <div id='panel_item'><ul style='display: block; margin:0; padding:0; margin-left:15px;'> <li class='homelist'><a href='http://www.geekarticles.com/article/The-W3C-XML-Schema-Specification-in-Context.html'>The W3C XML Schema Specification in Context</a></li></ul></div></div><div class='panel_wide_column'> <div id='panel_item'><ul style='display: block; margin:0; padding:0; margin-left:15px;'> <li class='homelist'><a href='http://www.geekarticles.com/article/Using-XML-to-Configure-Groove.html'>Using XML to Configure Groove</a></li></ul></div></div><div class='panel_wide_column'> <div id='panel_item'><ul style='display: block; margin:0; padding:0; margin-left:15px;'> <li class='homelist'><a href='http://www.geekarticles.com/article/XML-on-the-Cheap.html'>XML on the Cheap</a></li></ul></div></div><div class='panel_wide_column'> <div id='panel_item'><ul style='display: block; margin:0; padding:0; margin-left:15px;'> <li class='homelist'><a href='http://www.geekarticles.com/article/W3C-XML-Schema-Made-Simple.html'>W3C XML Schema Made Simple</a></li></ul></div></div></div><div class="spacer_big"> </div><h3>Sponsored Links</h3><script type="text/javascript"> <!-- microsoft_adunitid="1601"; microsoft_adunit_width="160"; microsoft_adunit_height="600"; microsoft_adunit_legacy="true";//--> </script> <script type="text/javascript" src="http://adsyndication.msn.com/delivery/getads.js" ></script><!-- <h3>Sponsored Links</h3> </div>--></div> <div class="spacer"></div> <div class="footer bottomlinks"> <p> <a href='http://www.geekarticles.com/about.html' class='vr'>About</a>  |   <a href='http://www.geekarticles.com/privacy.html' class='vr'>Privacy Policy</a>  |   <a title="Submit Resource" href="http://www.geekarticles.com/submit-resource.html">Submit Resource</a>  |   <a href="http://www.geekarticles.com/submit-article.html">Submit Article</a>  |   <a href='http://www.geekarticles.com/contact.html' class='vr'>Contact</a>  |   <a href='http://www.geekarticles.com/sitemap.html' class='vr'>Site Map</a><br> </p> <p class="btext">Copyright © 2009 GeekArticles.com. All Rights Reserved.</p> <p><span style='text-align: center;'><a href="http://www.copyscape.com/"><img style="margin: 10px 0 0 0; border-width:0px;" src="/images/cs-wh-3d-234x16.gif" alt="Page copy protected against web site content infringement by Copyscape" title="Do not copy content from the page. Plagiarism will be detected by Copyscape." width="234" height="16" /></a></span></p> </div> </div> <center> <!-- Start of Infolink ADs --> <script type="text/javascript"> var infolink_pid = 28546; var infolink_wsid = 10; </script> <script type="text/javascript" src="http://resources.infolinks.com/js/infolinks_main.js"></script> <!-- End of Infolink ADs --> </body> </html>