Archive for the ‘XPath’ Category

Cocoa Beta Release: XSLHelper

Monday, July 31st, 2006

XSLHelper screenshot

I don’t know of any native Cocoa XML IDEs for Mac OS X. That kinda sucks.

So the options for XSLT debuggers on OS X are kinda slim. There are some very full-featured Java-based IDEs that run on OS X, but the better ones are payware, and, well — they look like shit on OS X, frankly.

Lately, I’ve really been digging into XSLT and EXSLT, trying to learn more — specifically using libxslt. In February, I released a very basic XSLT debugger application called AquaXSL. AquaXSL was a really basic text editor in which you could edit a source XML document and a stylesheet, and they apply the stylesheet to the source doc and view the results in a couple of different (pretty) ways.

The problem with AquaXSL is that it’s a really basic (crappy) text editor. I don’t have the skills, time or inclination to create a nice text editor on the level of TextEdit.app, let alone something like BBEdit or TextMate. So therefore, AquaXSL kinda sucked.

So as I’ve lately been doing my XSLT thang… I started using Marc Liyanage’s excellent XSLT Glossary for BBEdit. This glossary basically turns BBEdit into a nice XSLT editor (but not debugger). You get auto-completion of all of XSLT and XPath 1.0’s elements, attributes and functions. This is the type of thing AquaXSL lacks, and will never gain.

So I found that I wanted to edit my XSLT and XML source docs in BBEdit (using Marc’s glossary) but wanted to apply the stylesheet and debug in something more full-featured than Safari or Firefox. Those browsers will apply the stylesheet and give you some very basic, but mostly cryptic error messages. That’s just not a very good debugging environment.

What I wanted was a little floating palette that seemed like it was a part of BBEdit (or TextMate for that matter) in which I could select my source and stylesheet docs, click a ‘Transform’ button, and see debugging info as well as the results in various formats.

So that’s what I made.

For now I’m calling it XSLHelper, but that will prolly change, as I plan to generalize it to XQuery as well as XSLT.

Usage is simple. Compose your XSLT stylesheet locally in your text editor of choice. Use an XSLHelper floating palette to select your source doc (local or remote) and stylesheet (also can be remote if you like). Then click the ‘Transform’ button to apply the stylesheet and see the results.

Results are displayed in raw text form, a pretty dynamic XML tree view, and also rendered as an HTML web page if possible/appropriate.

Also, debugging info is displayed in a text field, so errors are easier to fix.

I hope some of you will try it and send feedback. The only feature addition I’m planning for 1.0 is a dynamic table UI for adding runtime <xsl:params/> to a stylesheet. That should be out soon.

Download XSLHelper 1.0b1 (44kb).

XSLHelper is based on libxslt, libxml2, WebKit and NSXML.

XQuery as Web Scripting language

Tuesday, May 16th, 2006

Pretty wild idea by Martin Probst.

Martin talks about a JSP taglib for embedding XQuery directly in JSPs… that’s almost certainly too good an idea to pass up.

Tuesday Top 10

Tuesday, May 16th, 2006

The songs I’ll be jogging to tomorrow morning:

To generate the list above, I used iTunes -> File -> Export Song List and chose XML as the output format… this outputs to a hoary old XML serialization of a plist file. Here’s the XQuery I used to produce the HTML list above from the plist (using AquaQuery of course). This is not a bad way to get an HTML list from an iTunes playlist, BTW.

I had to insert the iTunes URLs by hand, as iTunes does not export the URL as a part of the XML unfortunately. All songs except the Madge/Gorillaz mash-up are from iTunes.


<ul>
{
for $song in /plist/dict/dict/dict
    let $title := $song/key[.="Name"]/following-sibling::string[1]/text()
    let $artist := $song/key[.="Artist"]/following-sibling::string[1]/text()
    return <li><a href="XXX">{$title}</a> - {$artist}</li>
}
</ul>

Lazy Sunday XML Links

Sunday, May 7th, 2006
  • An Introduction to RDF and the Jena RDF API. Jena is a “Semantic Web Framework” developed by HP Labs Semantic Web Programme which basically means, a Java API for RDF. Looks like they’re having a conference down the street this week. Wish I had dug into Jena a few months ago, so I’d have a good reason to take off work and go. This sort of topic interests me far more than microformats.
  • W3C RDF Primer. Related reading.
  • Special Characters in XSLT and Entities and XSLT both swiped from friend and co-worker Bill’s del.icio.us feed.
  • Apache ships version 1.0 of a new Java-based tree API for XML - AXIOM. Rather crowded space at this point… What’s the value proposition for a new tree API? Well, it sounds like AXIOM is built on a StAX/Pull (rather than SAX/Push) underlying parser which allows it to build subsections of the document tree as needed rather than the whole shebang, thus offering performance benefits. Via Cafe con Leche. XML God for Life Elliotte Rusty Harold (who has a competing product/API XOM) responded with what seems like fair criticism, and the Apache guys got kinda pouty.
  • Jenni’s XSLT Pages. I’m currently reading Jenni’s Beginning XSLT 2.0 and enjoying it despite the fact that it’s not the type of book I usually like. If you want to learn the practical details of using XSLT (with a focus on taking advantage of all the benefits 2.0 has to offer), I recommend the book. I’ve read through the non-reference portions of Mike Kay’s XSLT 2.0 Programmer’s Reference, which I actually enjoyed more… Kay’s book is definitely more in-depth and more interesting, but Jenni’s book takes a much more pragmatic approach and will probably get you using XSLT effectively more quickly. I recommend Jenni’s book first and then Michael’s (And I recommend reading Michael’s XPath 2.0 book before both).

Could you send that in XML?

Wednesday, May 3rd, 2006

A collegue pointed me to an interesting article extolling the virtues of microformats today. I tend not to be a fan of microformats, as they strike me as a kludgy way to achieve a subset of the functionality of XML, without nearly the expressive power. There’s something to be said for the 80/20 rule, but IMHO, microformats don’t get you there. Whatever, some people love them.

On the other hand, the discussion/arguments surrounding microformats are of interest to me, so I’m eager to read about them (plus their website is really slick).

A point this article seemed to take as a universally held opinion struck me as very odd though, and certainly wrong in my case. Here’s the passage that made my ears prick:

If I publish some information in a custom XML format for example, all consumers and intermediaries who process that information have to pay the XML complexity tax. They need to know about my custom schema, about validation, about stylesheets, about transformation and so on.”

“But what if I just want to see a piece of information or print it or search it or e-mail it or copy/paste it into my word processor? Should I have to pay the XML complexity tax for these simple requirements?”

Unless you are sending me an atomic piece of data like a number or a very small string, I’m certain I’d rather have the data marked up as XML. You need not send a schema… XML is human readable. But if you can send a schema, all the better. Even if I don’t need it now it may be of value to me in the future.

I’ve discovered that I would much rather receive any piece of non-trivial data marked up as XML rather than in it’s ‘raw’ form be it via a simple personal email or a web service. Why?

XQuery. That’s why.

Say you are sending me some movie listing info, that I just want to ‘copy/paste’ into another document. What if I want to format the data just a little bit, say add tabs or new lines or bullet points or something. Nothing extravagant, just a little formatting. Or, what if I want to format the data into executable code, say strings to be hardcoded into a JavaScript or Python program?

These types of data transformation are much much simpler and more flexible with structured data. Sure, you could try using some regexes to transform or alter the raw data, but it’s much easier to alter the data in both simple and complex ways using XQuery. XQuery totally blows away any raw text processing in power and even simplicity IMO. And on top of that, XQuery basics are very simple to learn.

There’ s just one missing piece of the puzzle: A simple, elegant, graphical tool for creating and executing your XQuery. hmmm… I wonder where you could find one.

I can’t stress enough how handy and convenient I find XQuery+AquaQuery for tackling small tasks or automating text processing. Even little one-off jobs.

I see no complexity tax for using XML for everyday data exchange. In fact, my experience is quite the opposite. Why all the XML hate?

Tricky tricky

Sunday, April 30th, 2006

When is


<true>1</true>

equal to


<false>1</false>

In XPath, that’s when.

Update

For that matter,


<true/>

is equal to


<false/>

in XPath (and therefore XQuery as well). Interesting. Both Element Nodes have the same string value. Specifically, the empty string.

XSLT Stylesheet for DHTML tree view of XML

Saturday, April 29th, 2006

You know how Firefox and IE provide a nice DHTML dynamic tree view of XML documents when you open them? You know how Safari doesn’t?

Here’s an XSLT stylesheet that should come pretty close to the same functionality. It’s not been thoroughly tested yet, but feel free to use and tweak.

Oh, and if you need a nice, free, Cocoa XSLT debugger to test this with, may I suggest AquaXSL.

stylesheet result screenshot


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://www.w3.org/1999/xhtml">

    <xsl:output method="xhtml" indent="yes"/>

    <xsl:template match="/">
        <html>
            <head>
                <style type="text/css">
                    /*<![CDATA[*/
                    body {
                        margin-left:-15px;
                    }
                    .TOD_element {
                        font-family:Monaco;
                        font-size:12px;
                        margin-left:15;
                        white-space:nowrap;
                    }
                    .TOD_content {
                        font-family:LucidaGrande;
                    }
                    .TOD_expandButton {
                        cursor:pointer;
                        padding:2px 5px;
                        -khtml-user-select:none;
                    }
                    .TOD_startOpenBracket,
                    .TOD_endOpenBracket,
                    .TOD_startCloseBracket,
                    .TOD_endCloseBracket {
                        color:black;
                    }
                    .TOD_startCloseBracket {
                        margin-left:15px;
                    }
                    .TOD_startElementName, .TOD_endElementName {
                        color:purple;
                        font-weight:normal;
                    }
                    .TOD_endElementName {
                    }
                    .TOD_attrName,
                    .TOD_attrEquals {
                        color:black;
                        font-weight:normal;
                    }
                    .TOD_attrValue,
                    .TOD_openAttrQuote,
                    .TOD_closeAttrQuote {
                        color:blue;
                    }
                    .TOD_comment,
                    .TOD_pi {
                        font-family:Monaco;
                        font-size:12px;
                        margin-left:30;
                    }
                    .TOD_comment {
                        color:gray;
                    }
                    .TOD_pi {
                        color:#449a9b;
                    }
                    /*]]>*/
                </style>
                <script type="text/javascript">
                    //<![CDATA[
                    function isShowing(el) {
                        return "none" != el.style.display;
                    }
                    function toggle(el) {
                        if (isShowing(el))
                            el.style.display = "none";
                        else
                            el.style.display = "";
                    }
                    function expand(expandButton) {
                        var expandArea = getNextSiblingByClassName(expandButton, "TOD_content");
                        toggle(expandArea);
                        if (isShowing(expandArea))
                            expandButton.innerHTML = "- ";
                        else
                            expandButton.innerHTML = "+ ";
                    }
                    function getNextSiblingByClassName(element, className) {
                        while (element = element.nextSibling) {
                            if (element.nodeType == Node.ELEMENT_NODE) {
                                if (-1 != element.className.indexOf(className)) {
                                    return element;
                                }
                            }
                        }
                        return null;
                    }
                    //]]>
                </script>
            </head>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="*">
        <div class="TOD_element">
            <span class="TOD_expandButton" onclick="expand(this);">-</span>
            <span class="TOD_startOpenBracket">&lt;</span>
            <span class="TOD_startElementName">
                <xsl:value-of select="name()"/>
            </span>
            <xsl:apply-templates select="@*"/>
            <span class="TOD_endOpenBracket">&gt;</span>            <span class="TOD_content">
            <xsl:apply-templates/>
            </span>
            <xsl:choose>
                <xsl:when test="count(*)">
                    <span class="TOD_startCloseBracket">&lt;/</span>
                </xsl:when>
                <xsl:otherwise>
                    <span class="TOD_leafStartCloseBracket">&lt;/</span>
                </xsl:otherwise>
            </xsl:choose>
            <span class="TOD_endElementName">
                <xsl:value-of select="name()"/>                </span>
            <span class="TOD_endCloseBracket">&gt;</span>        </div>
    </xsl:template>

    <xsl:template match="@*">
        <xsl:text> </xsl:text>
        <span class="TOD_attrName">
            <xsl:value-of select="name()"/>
        </span>
        <span class="TOD_attrEquals">
            <xsl:text>=</xsl:text>
        </span>
        <span class="TOD_openAttrQuote">
            <xsl:text>"</xsl:text>
        </span>
        <span class="TOD_attrValue">
            <xsl:value-of select="."/>
        </span>
        <span class="TOD_closeAttrQuote">
            <xsl:text>"</xsl:text>
        </span>
    </xsl:template>

    <xsl:template match="comment()">
        <div class="TOD_comment">
        <xsl:text>&lt;!-- </xsl:text>
        <xsl:value-of select="."/>
        <xsl:text> --&gt;</xsl:text>
        </div>
    </xsl:template>

    <xsl:template match="processing-instruction()">
        <div class="TOD_pi">
        <xsl:text>&lt;?</xsl:text>
        <xsl:value-of select="name()"/>
        <xsl:text> </xsl:text>
        <xsl:value-of select="."/>
        <xsl:text>?&gt;</xsl:text>
        </div>
    </xsl:template>

</xsl:stylesheet>

Lazy Sunday XML links

Sunday, April 16th, 2006

These may not be new, but if you hadn’t read them (like me) they’re new to you:

  • Comparing XSTL and XQuery by Michael Kay
  • While reading Item 30 Layer Functionality of Effective XML, I began fantasizing about an XML vocabulary for describing XML Processing Pipelines. The idea was so good that I was sure it was not an original one. I was right. Check out XPL.
  • The docs for NSXML, Apple’s Objective-C tree-based (think DOM-like) XML API have been updated and improved. Check out the under-appreciated features for binding XML documents directly to Graphical User Interfaces. Cool.
  • Item 35 of Effective XML, Navigate with XPath is available for reading online. This item has already saved me from naively attempting to access the text content of a DOM Element containing only text using el.firstChild.data. Read the item to see why this is almost guaranteed to fail eventually, perhaps even often. How long could debugging problems caused by that incorrect line have taken? A very long time. The weird thing is that I know DOM well enough to know better… but I had just committed this sin within the past 24 hours. Sometimes it takes an entertaining book like Effective XML to pound certain concepts into your thick skull, so that you don’t just ‘know’ them… you know them.