[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

Re: A Modest Proposal for the Re-inflation of XPath to an XML Syntax


Subject: Re: A Modest Proposal for the Re-inflation of XPath to an XML Syntax
From: Rick Geimer <rick.geimer@xxxxxxx>
Date: Thu, 19 Aug 1999 09:34:34 -0700

David,

While looking over the examples in your proposal, I had two thoughts. At
first, I thought the fully marked up expressions were really wordy, and
I wondered if anyone would actually create expressions this way. Then I
realized that, through the markup, I was finally able to understand some
of the more complex XPATH expressions. 

The current expression syntax is really the only thing I dislike about
XSL. It looks far too Perlish for me, and quickly becomes unreadable. To
borrow a phrase from the folks at OmniMark, anything slightly
complicated starts to look like modem noise (case in point
"ancestor-or-self::*[@$inherit][1]/@$inherit"). The only advantages to
it that I can see are:

1.	It is quick to type (assuming you can figure out what to type)
2.	It can be included directly in attributes

The major disadvantages are:

1.	Lack of readability (especially for non-programmers)
2.	No way to parse using standard XML tools
3.	No easy way to comment

Your examples, while a bit wordy, are in my opinion much easier to read,
and as you pointed out, easy to document with comments when things get
confusing. 

While it is almost certain that this will not make it into the XSLT 1.0,
I would like to see something in this vein incorporated into the next
release. 

Rick Geimer
National Semiconductor
rick.geimer@xxxxxxx




"Vun Kannon, David" wrote:
> 
> A Modest Proposal for the Re-inflation of XPath to an XML Syntax
> 
>         The language jointly used by Xpointer and XSLT, XPath, currently has
> a concrete reference syntax that is not the same as XML. This is perceived
> as a benefit because the syntax in use can be stored in the string
> representation of an attribute value. However, not using the instance syntax
> of XML does introduce some difficulties. All of the armamentarium and
> impedimenta of the XML arsenal, especially pointing, linking, the DOM and
> transformation, cannot be brought to bear on XPath expressions because they
> are not in XML syntax. The work of the XSchema WG is cast in XML at least in
> small part for these reasons.
>         Assuming that XPath expressions will always appear as attribute
> values makes it harder to treat them as first class objects. They are harder
> to name, therefore harder to reuse. They are harder to document, since
> comments cannot be interspersed within the expression. They are harder to
> address, because the apparatus necessary to locate and count their parts is
> not the same as XML's and cannot be assumed to be available. They are harder
> to parameterise therefore, and therefore doubly hard to reuse.
>         It may seem odd to harp on the reusability of XPath expressions. I
> believe that reusability is important. Reusability arises when considering
> the matter of idiom and "best practice". "not(position()=last())" is an
> important idiom in the creation of comma separated lists in text.
> "ancestor-or-self::*[@$inherit][1]/@$inherit" is a (parameterised) idiom for
> obtaining the right value for an attribute that is inherited and attachable
> anywhere in the node tree (overridable).
>         Other idioms are specific to the task, but appear multiple times in
> a document or stylesheet. Because idioms are important, are often best
> practices, they should be coded once and in a well documented way, such that
> new staff can be educated in their use, and changes to the idiom don't have
> to be hunted down in every instance document. In a similar manner,
> relational databases took a step forward in ease of use when they allowed
> stored procedures and triggers, which allowed SQL statements to be named,
> reused, and stored in the database, not in the source code of the programs
> that used them.
> 
>         A document using inflated XPath expressions would look like this:
> <template xpi:inflated-match="ID001">
>         <apply-templates/>
> </template>
> <xpi:path-expression id="ID001">
>         <root/>
> </xpi:path-expression>
> 
>         instead of this:
> <template match="/">
>         <apply-templates/>
> </template>
> 
>         where "xpi" is the "XPath Inflated" namespace, suitably defined.
> However, the URIs do not have to be anything as ugly and anti-mnemonic as
> ID001. They should more properly be "CSV" or "inherit?attr=color".
> 
>         While the up-translation of XPath to an XML syntax  can be
> undertaken by individuals in an ad hoc way, and suited only to their own
> purposes, I believe that it would benefit the XML-using community at large
> if there was an officially sanctioned way to describe XPath expressions in
> an XML instance syntax. The use of such a syntax would be optional, just as
> the use of the full or abbreviated syntax is a matter of choice.
>         Below I present a sketch of such a syntax by recasting each of the
> examples from the latest XPath WD in a manner of my own devising. I've tried
> to be consistent, but please do not let the failings of this attempt make
> you think less of the concept. I look forward to a discussion of the issues
> raised, in this and other forums as appropriate.
> Yours,
> David vun Kannon
> 
> child::para selects the para element children of the context node
> <child>para</child>
> 
> child::* selects all element children of the context node
> <child><element/></child>
> 
> child::text() selects all text node children of the context node
> <child><text/></child>
> 
> child::node() selects all the children of the context node, whatever their
> node type
> <child><node/></child>
> 
> attribute::name selects the name attribute of the context node
> <attribute>name</attribute>
> 
> attribute::* selects all the attributes of the context node
> <attribute><all/></attribute>
> 
> descendant::para selects the para element descendants of the context node
> <descendant>para</descendant>
> 
> ancestor::div selects all div ancestors of the context node
> <ancestor>div</ancestor>
> 
> ancestor-or-self::div selects the div ancestors of the context node and, if
> the context node is a div element, the context node as well
> <ancestor-or-self>div</ancestor-or-self>
> 
> descendant-or-self::para selects the para element descendants of the context
> node and, if the context node is a para element, the context node as well
> <descendant-or-self>para</descendant-or-self>
> 
> self::para selects the context node if it is a para element, and otherwise
> selects nothing
> <self>para</self>
> 
> child::chapter/descendant::para selects the para element descendants of the
> chapter element children of the context node
> <child>
>         chapter
>         <descendant>
>                 para
>         </descendant>
> </child>
> 
> child::*/child::para selects all para grandchildren of the context node
> <child>
>         <element/>
>         <child>
>                 para
>         </child>
> </child>
> 
> / selects the document root (which is always the parent of the document
> element)
> <root/>
> 
> /descendant::para selects all the para elements in the same document as the
> context node
> <root>
>         <descendant>
>                 para
>         </descendant>
> <root>
> 
> /descendant::olist/child::item selects all the item elements in the same
> document as the context node that have an olist parent
> <root>
>         <descendant>
>                 olist
>                 <child>
>                         item
>                 </child>
>         </descendant>
> </root>
> 
> child::para[position()=1] selects the first para child of the context node
> <child>
>         para
>         <predicate>
>                 <equal>
>                         <position/>
>                         <number>1</number>
>                 </equal>
>         </predicate>
> </child>
> 
> child::para[position()=last()] selects the last para child of the context
> node
> <child>
>         para
>         <predicate>
>                 <equal>
>                         <position/>
>                         <last/>
>                 </equal>
>         </predicate>
> </child>
> 
> child::para[position()=last()-1] selects the last but one para child of the
> context node
> <child>
>         para
>         <predicate>
>                 <equal>
>                         <position/>
>                         <minus>
>                                 <last/>
>                                 <number>1</number>
>                         </minus>
>                 </equal>
>         </predicate>
> </child>
> 
> child::para[position()>1] selects all the para children of the context node
> other than the first para child of the context node
> <child>
>         para
>         <predicate>
>                 <greater-than>
>                         <position/>
>                         <number>1</number>
>                 </greater-than>
>         </predicate>
> </child>
> 
> following-sibling::chapter[position()=1] selects the next chapter sibling of
> the context node
> <following-sibling>
>         chapter
>         <predicate>
>                 <equal>
>                         <position/>
>                         <number>1</number>
>                 </equal>
>         </predicate>
> </following-sibling>
> 
> preceding-sibling::chapter[position()=1] selects the previous chapter
> sibling of the context node
> <preceding-sibling>
>         chapter
>         <predicate>
>                 <equal>
>                         <position/>
>                         <number>1</number>
>                 </equal>
>         </predicate>
> </preceding-sibling>
> 
> /descendant::figure[position()=42] selects the forty-second figure element
> in the document
> <root>
> <descendant>
>         figure
>         <predicate>
>                 <equal>
>                         <position/>
>                         <number>42</number>
>                 </equal>
>         </predicate>
> </descendant>
> </root>
> 
> /child::doc/child::chapter[position()=5]/child::section[position()=2]
> selects the second section of the fifth chapter of the doc document element
> <root>
>         <child>
>                 doc
>                 <child>
>                         chapter
>                         <predicate>
>                                 <equal>
>                                         <position/>
>                                         <number>5</number>
>                                 </equal>
>                         </predicate>
>                         <child>
>                                 section
>                                 <predicate>
>                                         <equal>
>                                                 <position/>
>                                                 <number>2</number>
>                                         </equal>
>                                 </predicate>
>                         </child>
>                 </child>
>         </child>
> </root>
> 
> child::para[attribute::type="warning"] selects all para children of the
> context node that have a type attribute with value warning
> <child>
>         para
>         <predicate>
>                 <equal>
>                         <attribute>type</attribute>
>                         <string>warning</string>
>                 </equal>
>         </predicate>
> </child>
> 
> child::para[attribute::type='warning'][position()=5] selects the fifth para
> child of the context node that has a type attribute with value warning
> <child>
>         para
>         <predicate>
>                 <equal>
>                         <attribute>type</attribute>
>                         <string>warning</string>
>                 </equal>
>         </predicate>
>         <predicate>
>                 <equal>
>                         <position/>
>                         <number>5</number>
>                 </equal>
>         </predicate>
> </child>
> 
> child::para[position()=5][attribute::type="warning"] selects the fifth para
> child of the context node if that child has a type attribute with value
> warning
> <child>
>         para
>         <predicate>
>                 <equal>
>                         <position/>
>                         <number>5</number>
>                 </equal>
>         </predicate>
>         <predicate>
>                 <equal>
>                         <attribute>type</attribute>
>                         <string>warning</string>
>                 </equal>
>         </predicate>
> </child>
> 
> child::chapter[child::title='Introduction'] selects the chapter children of
> the context node that have one or more title children with string-value
> equal to Introduction
> <child>
>         chapter
>         <predicate>
>                 <equal>
>                         <child>title</child>
>                         <string>warning</string>
>                 </equal>
>         </predicate>
> </child>
> 
> child::chapter[child::title] selects the chapter children of the context
> node that have one or more title children
> <child>
>         chapter
>         <predicate>
>                 <child>title</child>
>         </predicate>
> </child>
> 
> child::*[self::chapter or self::appendix] selects the chapter and appendix
> children of the context node
> <child>
>         <element/>
>         <predicate>
>                 <or>
>                         <self>title</self>
>                         <self>appendix</self>
>                 </or>
>         </predicate>
> </child>
> 
> child::*[self::chapter or self::appendix][position()=last()] selects the
> last chapter or appendix child of the context node
> <child>
>         <element/>
>         <predicate>
>                 <or>
>                         <self>title</self>
>                         <self>appendix</self>
>                 </or>
>         </predicate>
>         <predicate>
>                 <equal>
>                         <position/>
>                         <last/>
>                 </equal>
>         </predicate>
> </child>
> 
> child::div/child::para selects the para element children of the div element
> children of the context node, or, in other words, the para element
> grandchildren that have div parents
> <child>
>         div
>         <child>
>                 para
>         </child>
> </child>
> 
> child::para[position()=1], child is the name of the axis, para is the node
> test and [position()=1] is a predicate
> <child>
>         para
>         <predicate>
>                 <equal>
>                         <position/>
>                         <number>1</number>
>                 </equal>
>         </predicate>
> </child>
> 
> para selects the para element children of the context node
> <child>para</child>
> 
> * selects all element children of the context node
> <child><element/><child>
> 
> text() selects all text node children of the context node
> <child><text/></child>
> 
> @name selects the name attribute of the context node
> <attribute>name</attribute>
> 
> @* selects all the attributes of the context node
> <attribute><all/></attribute>
> 
> para[1] selects the first para child of the context node
> <child>
>         para
>         <predicate>
>                 <equal>
>                         <position>
>                         <number>1</number>
>                 </equal>
>         </predicate>
> </child>
> 
> para[last()] selects the last para child of the context node
> <child>
>         para
>         <predicate>
>                 <equal>
>                         <position>
>                         <last/>
>                 </equal>
>         </predicate>
> </child>
> 
> */para selects all para grandchildren of the context node
> <child>
>         <element/>
>         <child>
>                 para
>         </child>
> </child>
> 
> /doc/chapter[5]/section[2] selects the second section of the fifth chapter
> of the doc
> <root>
>         <child>
>                 doc
>                 <child>
>                         chapter
>                         <predicate>
>                                 <equal>
>                                         <position/>
>                                         <number>5</number>
>                                 </equal>
>                         </predicate>
>                         <child>
>                                 section
>                                 <predicate>
>                                         <equal>
>                                                 <position/>
>                                                 <number>2</number>
>                                         </equal>
>                                 </predicate>
>                         </child>
>                 </child>
>         </child>
> </root>
> 
> chapter//para selects the para element descendants of the chapter element
> children of the context node
> <child>
>         chapter
>         <descendant-or-self>
>                 <node/>
>                 <child>
>                         para
>                 </child>
>         </descendant-or-self>
> </child>
> 
> //para selects all the para descendants of the document root and thus
> selects all para elements in the same document as the context node
> <root>
>         <descendant-or-self>
>                 <node/>
>                 <child>
>                         para
>                 </child>
>         </descendant-or-self>
> </root>
> 
> //olist/item selects all the item elements in the same document as the
> context node that have an olist parent
> <root>
>         <descendant-or-self>
>                 <node/>
>                 <child>
>                         olist
>                         <child>
>                                 item
>                         </child>
>                 </child>
>         </descendant-or-self>
> </root>
> 
> . selects the context node
> <self><node/></self>
> 
> .//para selects the para element descendants of the context node
> <self>
>         <node/>
>         <descendant-or-self>
>                 <node/>
>                 <child>
>                         para
>                 </child>
>         </descendant-or-self>
> </self>
> 
> .. selects the parent of the context node
> <parent><node/><parent/>
> 
> ../@lang selects the lang attribute of the parent of the context node
> <parent>
>         <node/>
>         <attribute>
>                 lang
>         </attribute>
> </parent>
> 
> para[@type="warning"] selects all para children of the context node that
> have a type attribute with value warning
> <child>
>         para
>         <predicate>
>                 <equal>
>                         <attribute>type</attribute>
>                         <string>warning</string>
>                 </equal>
>         </predicate>
> </child>
> 
> para[@type="warning"][5] selects the fifth para child of the context node
> that has a type attribute with value warning
> <child>
>         para
>         <predicate>
>                 <equal>
>                         <attribute>type</attribute>
>                         <string>warning</string>
>                 </equal>
>         </predicate>
>         <predicate>
>                 <equal>
>                         <position/>
>                         <number>5</number>
>                 </equal>
>         </predicate>
> </child>
> 
> para[5][@type="warning"] selects the fifth para child of the context node if
> that child has a type attribute with value warning
> <child>
>         para
>         <predicate>
>                 <equal>
>                         <position/>
>                         <number>5</number>
>                 </equal>
>         </predicate>
>         <predicate>
>                 <equal>
>                         <attribute>type</attribute>
>                         <string>warning</string>
>                 </equal>
>         </predicate>
> </child>
> 
> chapter[title="Introduction"] selects the chapter children of the context
> node that have one or more title children with string-value equal to
> Introduction
> <child>
>         chapter
>         <predicate>
>                 <equal>
>                         <child>title</child>
>                         <string>Introduction</string>
>                 </equal>
>         </predicate>
> </child>
> 
> chapter[title] selects the chapter children of the context node that have
> one or more title children
> <child>
>         chapter
>         <predicate>
>                 <child>title</child>
>         </predicate>
> </child>
> 
> employee[@secretary and @assistant] selects all the employee children of the
> context node that have both a secretary attribute and an assistant attribute
> <child>
>         employee
>         <predicate>
>                 <and>
>                         <attribute>secretary</attribute>
>                         <attribute>assistant</atttribute>
>                 </and>
>         </predicate>
> </child>
> 
> *****************************************************************************
> The information in this email is confidential and may be legally privileged.
> It is intended solely for the addressee. Access to this email by anyone else
> is unauthorized.
> 
> If you are not the intended recipient, any disclosure, copying, distribution
> or any action taken or omitted to be taken in reliance on it, is prohibited
> and may be unlawful. When addressed to our clients any opinions or advice
> contained in this email are subject to the terms and conditions expressed in
> the governing KPMG client engagement letter.
> *****************************************************************************
> 
>  XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list



Current Thread
Keywords