XML Editing: A WYSIWYG XML Document Editor
Summary: Describes Microsoft Internet Explorer 6 behavior used to implement a demo WYSIWYG XML document editor, shows features that make WYSIWYG XML content editing easy and familiar to word processor users, and makes native XML editing available with edit view icons to access control attributes or fields in the underlying XML document. (13 printed pages)
A WYSIWYG (What You See Is What You Get) XML editor? Your initial reaction may be to think that this is something of an oxymoron. After all, isn't XML supposed to separate data and presentation? True, but in practice, if the XML is to be rendered to HTML at some point, it is still often useful to work with the XML while viewing it in one or more of its eventual target presentation formats.
In this article, you'll be taking a look at a demo XML editor that provides such a view, implemented entirely as a behavior in Internet Explorer 6. This editor demonstrates a number of concepts that make WYSIWYG XML content editing comfortable and familiar, putting native XML editing into the hands of any user who can use a traditional word processor.
Figure 1. WYSIWYG XML Document Editor
You will get to see the demo of the editor right in your browser (if you already have Internet Explorer 6 installed) as I step you through the various features. I'll talk about how the editor works, about the code behind the behavior, and discuss briefly how the "edit views" for the editor are created. But first, here's a little background information on XML editing.
XML editing is still very much an emerging technology. XML itself is widely recognized in the computer industry as a useful format for representing data and for moving data between systems. Many powerful new tools have been created for working with XML, and many more tools are offering XML as an optional output format. A handful of specialized new tools have emerged which provide a friendly word processor-like interface for editing XML. These allow users to create and edit XML content without ever being aware that they are working with XML as the underlying technology.
Structured document editing
In addition to simply allowing users to work with data in XML format, XML editing provides a framework for what is known as structured document editing. While the concept of structured document editing has been around for years, and indeed such editors were written using SGML (a precursor to XML), only now with XML technologies reaching critical mass are we likely to see structured document editing really come into its own.
A structured document is what it sounds like. In current word processors you can decide to break your document into chapters, but then it's pretty much up to you what you want to put in each chapter. Maybe you remember to type in an abstract for some chapters, or maybe you don't. In a structured document, an abstract might be defined as a required component of a chapter, and a structured document editor then gently exposes this to the end user in such a way that they must provide a valid abstract in order to have a valid document. The real power of a structured document editor lies in the fact that it exposes the valid operations on a document depending on where the user is in that document, guiding the user through the process of creating a document which has a specific defined format, a document which therefore can be much more easily machine-processed using the rich array of downstream XML technologies.
Tags are for nerds!
The trick in structured document editing then lies in finding intuitive ways in which to expose the document structure to the user. Some XML editors attempt to do this by exposing all the XML tags to the user, or by simultaneously exposing document parameters in helper windows off to the side. In my humble opinion, however, no normal user should ever be exposed to the bewildering array of tags that underlie an XML document or all the nitty-gritty details of the document structure at every point in the document. Although the plumbing has to be there, the average user should not have to see it.
Furthermore, an XML document often contains underlying metadata that the user may not always want to or need to see. Or they may only need to access such metadata on occasion. This raises the issue of how to present the additional data to the user without cluttering the presentation.
In my editor demo, I'll demonstrate a handful of ideas related to exposing structured document functionality to the user but without resorting to a "tag on" view and without inundating the user with extraneous information. I will certainly not pretend that this approach will solve all the world's problems, and in fact it should be made clear that the usability testing on this editor demo consists mostly of a test group of me, myself, and I. Nevertheless, I hope you'll find some of the ideas at least vaguely intriguing. But enough talk—on to the demo.
The demo code provided with this article implements an XML editor with quite a bit of interesting functionality. That said however, let me make sure to set your expectations appropriately. This editor as provided is no more than a one-person pet project, and while it does some fun tricks and runs the demo scenarios reasonably well, do not expect the editor to be of production quality. In other words, don't throw away your current word processor yet. Yes, I used the editor to write this article, but frankly, it was only a mother's love that gave me the patience to work around some of its current limitations. OK, that should be about enough of a disclaimer.
If you do not already have Internet Explorer 6 installed on your computer, you'll need to update your browser before trying the demo:
- Install Internet Explorer 6
If you already have Internet Explorer 6 on your computer, the following link will open the XML editor demo in a new window. Refer back to this window for instructions to help you navigate through the demo.
- Run the XML editor demo
When the demo launches, you will be looking at an example news story. Try clicking any of the text areas to convince yourself that you're really editing a document. While permissions prevent the in-browser demo from saving to an actual file, you can click the "show XML" link in the upper right at any time to see the effects of your edits on the underlying XML.
Note A very simple version of the editor as an .hta is provided in the code download for this article. That version will allow you to both load and save XML documents.
If you want a more detailed description of the demo, read on, but if you just want to dive in and explore, use the toolbar drop-down list to select the different demo documents, and then try clicking and right-clicking the icons within the documents to expose various editor features.
So the purpose of the aforementioned icons sprinkled around the document is to expose the "drill down" points in the document or regions with specific functionality. As your cursor hovers over an icon, tooltip pop-up text provides a hint as to the purpose of that particular icon. Right-clicking these icons will expose options associated with a particular content element, such as the ability to move the item, add other peer content elements, delete the particular element, or display optional alternate views of the item, all depending on the underlying document structure and/or the characteristics exposed in the edit view.
For instance, there are two icons near the main image for the news story. Use the cursor to hover over the top icon to see the tooltip, Layout Selection. Right-click the icon and then click layout select.
This exposes a combo box that is tied to an attribute in the XML document called layout. Presumably, downstream XSLT stylesheets could use this attribute to decide how to render the top part of the page layout. Try selecting different values from the combo box and note how the editor makes corresponding adjustments to the layout of the top-of-page region. You can restore a normal view by again right-clicking that icon and selecting the default view or by clicking the Undo button in the toolbar.
Images and multiple node "observers"
Now, use the cursor to hover over the Art icon directly above the main image of me coming in for a landing (you can verify this by seeing the Art tooltip appear.) Right-click this icon and click details. The art element redraws, exposing the underlying document attributes for the image, such as the URL, caption, and alignment (not used in this particular instance).
Try changing the URL by adding a '2' to the file name, changing it from img/zip.jpg to img/zip2.jpg. As you leave the field, the node in the XML document is updated and the image widget that is watching the same node instantly updates itself. Similarly, in the Caption field, try changing the caption text. As you tab out of that field, the caption on the right side of the image update as well. Of course, you can edit the caption directly on the page and as you tab out of it, the text box in the details view will update. The editor can attach any number of visual elements to any XML node and it will manage updating them all as needed when the XML node changes. Note that in this position, the Align drop-down list box does not do anything. The layout of the art item is in this case controlled by the surrounding table structure. Further down in the new story demo, however, you can see the Align attribute in action.
Unlimited undo and redo
The editor also supports unlimited undo/redo via the buttons in the toolbar area. Try clicking the Undo button a few times and watch as your changes roll back. Then try hitting Redo and watch them reinstate themselves.
Multiple top-level views
You'll notice an icon in the far upper-left corner of the document. Right-click this icon and select mobile to completely change the view of the document and work in a view simulating the layout on a mobile device. You'll notice that the document remains fully editable and that any changes you make are carried back to the main view when you switch back.
Inserting, deleting, and moving items
Return to the main view again by right-clicking the far upper-left icon and select desktop. Scroll down the page to the pullquote with the bright red type on the left side of the page, where Peter Seidenspinner comments on his experience. Right-click the icon just above the pullquote and note that it exposes a number of items that you can insert into the column, as well as exposing the option to delete the pullquote itself. This is an example of how the document exposes structure via the editor so the user knows what can and can't be placed in the document at that point.
Next, insert a new Advertisement. A default ad appears above the pullquote. Click the icon above the ad and to look at the Advertisement menu. You'll see you can move the ad below the pullquote by clicking ↓move down. Do that and the ad jumps below the pullquote. If you right-click the icon above the ad and then click delete, the ad will disappear. Right-clicking the pullquote icon and clicking delete there as well results in an empty column. A +add icon appears to allow you to repopulate the column if desired.
Context-sensitive text effects
Next, try stroking some text to select it at various places in the document. Depending on where you're at, you may see the bold, underline, and italics buttons light up in the toolbar area or some subset thereof. Some text areas in the document permit only italic style to be applied: the deck (below the headline) and lead will only allow italics. The headline itself does not allow any text effects. Paragraphs down in the main body, however, allow all three effects. This is all based on the information provided in the edit view for the document. You make the rules about what styles are allowed where and the editor enforces them. And you can create any type of custom tagging you want—this is XML after all.
An entertaining aspect of the way the editor renders the various existing text effects is that the boundaries of a particular region are set off by a light dashed line. I personally find this very useful. How many times have you put your cursor down in some white space next to a bolded word expecting to get non-bold text only to find you'll picking up leftover bolding? With this outlining effect, you can see clearly which text region you're typing in and therefore which text effect you'll be using. Place the cursor in the middle of some text and then try pressing Tab or Shift+Tab to move forward and backwards to select adjoining text runs—note how the runs are identified by the dashed outline.
The light gray horizontal bars crossing the page delineate the boundaries between segments, areas of the page that have distinct column formats. These are simply a function of the particular demo document design and are not intrinsic to the editor. By right-clicking one of the icons in the gray segment bars, you can insert new segment types. You can also perform the same types of actions on segments that you could on the content items within columns, such as moving whole segments up and down, and deleting entire segments.
Although the icons are small and not terribly intrusive, you can quickly view the document without icons by clicking the Hide Icons button on the editor toolbar. All the icons will disappear leaving you with a clean WYSIWYG view of your document. Click the Show Icons button to restore them.
Non-linear edit displays
Now let's move to a different demo document. Click the drop-down list box in the editor toolbar and select the Slide Show document. As you do this, the editor goes to the Web server to fetch the new XML instance document, and then it loads the new edit view document.
I picked a Slide Show as an example of a type of content where simply laying out a linear edit view is clearly not the best user-friendly format. If you click the Show XML link to the right of the editor toolbar, you'll see that the underlying XML consists of a repeated sequence of slide definitions, but the preference is not to display it as a long scroll for editing. Instead, it is shown close to its eventual format, where you see the slides (and their associated meta data) change in place as you click the slide numbers.
You can use the techniques you've already learned to change the order of slides and to insert and delete slides. And everything is editable in place—even the title of the slide show.
Return to the drop-down list box and select the Enrollment Demo. This is a trivially simple example of an XML editor providing an interface to something more akin to a business form as opposed to the previous content scenarios. Again, you can use the techniques you learned to add new student rows to the table, remove students, and move students up and down in the list, and edit their individual data.
Eating my own dog food
Finally I've included a quick stripped-down scenario for editing a prospective MSDN article. In the Microsoft tradition, this is in fact what I used to write this article. There's nothing particularly new about this document, but it's interesting to watch how the Table of Contents instantly updates when you edit a section name and vice versa.
To begin to understand how the editor works, let's follow an XML document through the loading process. When the XML document editor is given the URL or path of an XML file to load, it first attempts to fetch that file and load it into the MSXML DOM. I'll refer to this document as the instance document.
If the instance document is successfully loaded, the editor then looks for a special processing instruction at the top of the instance document specifying an "edit view" file to use to build an editable view on the document. An "edit view" file is just another XML file that provides all the information the editor needs to construct this WYSIWYG editable view. (The format and construction of edit views will be briefly discussed in the next section).
If the edit view file is successfully located, it also is loaded into a second MSXML DOM. The edit view is in many ways similar to an XSLT stylesheet in that it provides a series of XHTML templates for each possible type of item in the instance document. Why didn't I just use XSLT? Two reasons: first of all, XSLT is quite complex and I would not have been able to support anywhere near the full range of XSLT functionality in "pet project" timeframe. Second, and more importantly, XSLT doesn't have provisions for capturing some of the things needed to perform interactive editing, such as a way to specify initial fragments to insert when creating a new complex element, etc.
After successfully loading both the instance document and the edit view document, the editor then begins by matching the root template of the edit view with the root of the instance document and fetching the associated chunk of XHTML. The editor recognizes certain expando properties on certain nodes in the root XHTML and begins recursively loading more XHTML fragments into these wrapper nodes, associating them with the underlying XML nodes in the instance document DOM as it goes. When the recursive knitting process is complete, the entire XHTML is loaded into Internet Explorer as the inner HTML for the editor DIV in the host editor document.
For example, here's the main DIV that is bound to the
edx editor behavior:
<div class=edx id=edxid onEdxDocumentChange="docChange();" onEdxSelectionChange="selChange();" edxtemplate=root xmlurl="newsstory/newsstory.xml" onncontextmenu="return false;"><br/><br/>Loading...</div>
While the editor is performing the initial load operation, you see the Loading... message. Once the initial XHTML has been built, it is loaded into this DIV as its innerHTML, and Internet Explorer displays the fully editable document in the place previously occupied by the loading message.
After the XHTML is placed as HTML into this DIV, the editor performs a final bookkeeping pass to associate the newly instantiated HTML DOM nodes with their associated XML nodes, and then editing may begin.
As certain editing operations make it necessary to redraw areas of the document, the exact same process is followed to reload any necessary subset of the document. The editor uses an observer design pattern to "watch" XML nodes that are bound to visual edit areas in the HTML view. Thus, a given node can be displayed in multiple places in the document, and editing it in one place causes it to automatically reload in any other position where it is used.
You may be wondering where XSD schema fits in all this. Actually, the editor itself does not require an XSD schema to edit a document. One may certainly be provided, but it is entirely optional. The editor gets all the information it needs to edit the instance document from the edit view document. The edit view document implies the necessary schema by its own structure while also supplying specific information to the editor about how to display certain UI to the user at various points in the document. Certainly, there are some things that you can express in schema that this demo editor cannot handle, but the editor can edit a significant and useful subset of documents that can be expressed using XSD schema. And certainly the editor could be made genuinely schema-aware. Leaf node schema checking would be relatively trivial to add, but adding full structural schema awareness would probably exceed this author's available quantity of pet project time!
If you are already familiar with XSLT stylesheets, you will find building edit views fairly straightforward. If not, you might want to consider first familiarizing yourself a bit with XSLT. There is plenty of good literature out there. Here's one tutorial:
- XSLT Tutorial
As with XSLT, you will be defining templates to map onto specific nodes in your desired XML instance document. As mentioned above, templates are often recursive in nature, and templates may in turn invoke other templates to build up their internal structure.
There are four basic template types that the editor recognizes. These are regions, containers, and two built-in types, widgets and fields. It is your job to define regions and containers, and these in turn may use the built-in widget and field templates to provide the actual leaf-node edit functionality. Built-in templates may be distinguished because they have a colon in the template name, for instance widget:icon or field:flow.
Let's start with an example based on the Enrollment document in the demo. Suppose you have the following XML instance document you want to edit:
<?xml version="1.0" encoding="UTF-8"?> <?edxview enroll-view.xml?> <enroll> <class-name>Creative Writing 101</class-name> <teacher-name>Shultz</teacher-name> <room-number>#202</room-number> <students> <student> <last-name>Chandler</last-name> <first-name>Raymond</first-name> <ssn>111-11-1111</ssn> </student> <student> <last-name>Balzac</last-name> <first-name>Honore</first-name> <ssn>222-22-2222</ssn> </student> </enroll>
First of all, note the processing instruction above that associates the instance document with the edit view document. A stripped down version of enroll-view.xml follows, with the extraneous HTML formatting stripped out.
<?xml version="1.0" encoding="UTF-8"?> <editviews xmlns:edx="msnbc-edx-edit-view"> <edx:view uiname="Main Edit View"> <edx:template name="root" type="region" uiname="Entire Document"> <edx:xhtml display="default"> <h3>Class Enrollment Form</h3> Class Name: <span edxtemplate="field:flow" edxpath="/enroll/class-name"/><br/> Teacher Name: <span edxtemplate="field:flow" edxpath="/enroll/teacher-name"/><br/> Room #: <span edxtemplate="field:flow" edxpath="/enroll/room-number"/><br/> <table style="border:1px solid #6666cc"> <thead> <tr bgcolor="#cce0ff"> <th bgcolor="white"></th> <th align="center">Last Name</th> <th align="center">First Name</th> <th align="center">Social Security Number</th> </tr> </thead> <tbody edxtemplate="students" edxpath="/enroll/students"></tbody> </table> </edx:xhtml> </edx:template> <edx:template name="students" type="container" uiname="Student List"> <edx:match element="student"> <tr edxtemplate="student" edxpath="."></tr> </edx:match> </edx:template> <edx:template name="student" type="region" uiname="Student"> <edx:xhtml display="default"> <td><img edxtemplate="widget:icon"/></td> <td><span edxtemplate="field:flow" edxpath="last-name"></span></td> <td><span edxtemplate="field:flow" edxpath="first-name"></span></td> <td><span edxtemplate="field:flow" edxpath="ssn"></span></td> </edx:xhtml> <edx:insert> <student> <last-name>[last name]</last-name> <first-name>[first name]</first-name> <ssn>[ssn]</ssn> </student> </edx:insert> </edx:template> </edx:view> </editviews>
The edit view document starts out with a template with a name of root. This is the template that the editor will try to associate with the root node of the instance document. This first template is of type region indicating that it is a block of XHTML that will be more or less directly loaded into Internet Explorer to render a portion of the edit view. Within a given template you may have multiple XHTML fragments to provide different editing perspectives on a particular region. In this case, however, there is only one called default.
The XHTML looks like fairly normal HTML except that it is well-formed XML, and it has a few little extra expando props such as the edxtemplate and edxpath attributes. This is how nodes in the edit view are associated with nodes in the XML instance document, and also how the editor recursively knits together the XHTML snippets.
In the first span, we see the attributes to associate that span with the class-name node in the XML document, and we see it using the built-in template of field:edit, the basic editing component provided by the editor.
The next two spans are similar, directly associating themselves with nodes in the XML document and using the field:edit component to allow the user to modify their values.
Then things get a little more interesting. We see the TBODY tag being associated with an edxtemplate named students, and we can look below and see where this template is declared in the edit view document. This template is of type container, which means that it will expand dynamically depending on the number of child nodes in the XML instance document. You may wonder about the use of the TBODY tag as it's not that commonly seen in HTML markup. TBODY is actually the real parent tag for TR tags in a table. We use it here specifically because the HTML tag which is being turned into a container must be the direct parent of the HTML tags it will contain, and if we tried to attach the container to the TABLE tag, Internet Explorer 6 would silently and magically insert a TBODY tag, breaking the desired wrapping. Other tags can certainly be containers. Look through the other demo edit view templates to see examples of DIV and SPAN containers, to name a few. But the important thing is that tag needs to be the immediate outer parent of the HTML tags specified in the match spec in a container. But I'm getting ahead of myself.
Looking down now at the students container template, we see that it is a bit different from the template for a region. Whereas a region lays out a block of XHTML to be use to build a visual rendering, the container is merely a connector, matching XML nodes to XHTML nodes which will be further expanded based on the child nodes found in the XML document. In this trivial case, the container only recognizes one type of child node, but other example documents in the demo show how containers can house multiple types of content elements.
When the students container instantiates a new child, it gets the student template, another template of type region, and uses that to flesh out the display for each one of the children. Note that in the student region, in addition to the XHTML fragment, also contains an insertion fragment. This is what the parent container uses to create a new instance of a child, should the user decide to make a brand new entry. And again in this template we see references to the built-in templates of field:flow and widget:icon. The icon built-in widget displays the icon that enables the drill-down functionality in the editor. Refer to the running enrollment demo to see how these icons enable the move up, move down, insert, and delete functions on the rows in the students table.
There is quite a bit more to edit view creation, and if this was a production-ready editor, it would certainly bear a much more detailed explanation. But this general outline combined with the several functional examples provided with the demo documents should allow you to gain a reasonable understanding of the process.
As I mentioned above, the editor is implemented as a behavior. If you're unfamiliair with the basic concept of behaviors in Internet Explorer, you can learn more about them in the following content:
The file Edx.htc provides the outer implementation of the behavior. It in turn includes nine Microsoft JScript files that separate the functional elements of the editor into a handful of classes. I must admit it's a bit unusual to tackle a project of this relative level of complexity in JScript, but it's actually fairly easy to do a clean job of writing object oriented code in JScript, and Microsoft® Visual InterDev® makes debugging a breeze. The editor is surprisingly snappy, all things considered, but I credit this mostly to the fact that the JScript spends most of its time leveraging the muscle of the APIs in MSXML and Internet Explorer 6.
The code's main job is to build and maintain a mapping between the XML instance document, the HTML editing display, and a tree of objects linking the two. Thus you can think of the editor as maintaining three trees in synchonization as the user performs various editing operations. Yes, keeping this all straight can at times be a little tricky, especially considering the mappings are not all one-to-one.
Tip If you set the edxoptions property on the main editor DIV to debug:true, it turns on an automatic sanity check scan of these mappings which runs every second. Although if performs quite a bit of verification it doesn't appear to affect the actual interactivity of the editor. So if you decide to try playing with the code, I'd strongly recommend enabling this feature.
Key editor classes
I won't spend a great deal of time diving into the guts of the editor, but here are a few high-level overview items of interest. The main object that defines a node mapping is called an edxnode. This is the base class, and region, container, field, and widget all inherit from edxnode. The root class is in turn a special case of a region with a little added functionality since it needs to export a few additional methods and properties to the outer behavior. The field and widget classes are the only ones which actually provide any actual leaf node editing, with the widget class providing such sundries as select boxes, text boxes, the magic icons, etc.
Another class of particular interest is the xmlmgr (XML manager). This class provides the layer of access to the underlying XML DOM in a manner to enable the n-level Undo/Redo features. All operations against the XML tree are performed in a way such that they can be fully mirrored. Multi-step operations against the XML DOM are captured in simple reversible transactions, and when the user clicks Undo, the transaction's mirror images are run to revert to the desired previous state. And Redo then runs the mirrors of the mirrors.
Saving files with Editor.hta
Finally, I've included a very minimal HTA version of the editor that is capable of actually saving out files. The Editor.hta application is included in the code download. The UI for loading and saving files is abysmal, but it does at least demonstrate that the editor is capable of saving out and reloading documents. I'm using it right now, actually!
I hope my little XML editor demo has given you a few insights into the evolving world of XML document editing and structured document editing in general. Maybe you even got a few ideas about using larger scale behaviors in Internet Explorer.
Most importantly, I hope you see clearly that XML is not just for machines, not just for middle-layer data processing and exchange—XML can be for humans, too. Many of those one-off editing tasks you've been solving with custom Microsoft® Visual Basic® or Web applications for can probably soon be taken over by a general purpose XML editor. The advantage to you is you will have less custom applications to write and maintain, and the advantage to end users is they only need to learn one tool instead of remembering the idiosyncrasies of each of those aforementioned one-off applications. And since presentation and data representation are nicely separated, you will be able to more easily adapt to changing visual designs without having to do "real programming." A few tweaks to an edit view document and likely you can quickly provide the latest "new look" being asked for by your department.
And once you've converted your human content creation or data capture operations to XML using XML document editing, the advantages downstream are well known: XML is truly a portable and universal data format.