- From: Vun Kannon, David <dvunkannon@kpmg.com>
- Date: Fri, 20 Aug 1999 14:37:14 -0400
- To: "'www-xpath-comments@w3.org'" <www-xpath-comments@w3.org>
Sirs - I am forwarding to you a message I posted recently to xsl-list. Please consider it a suggestion for inclusion in the XPath specification. I appreciate that XPath and XSLT are in last call, however, my suggestion doesn't change the power of the XPath language, only it's expression. I understand the time pressure you are under, so I don't expect direct feedback. Thank you, David vun Kannon -----Original Message----- From: Vun Kannon, David [mailto:dvunkannon@kpmg.com] Sent: Wednesday, August 18, 1999 11:13 PM To: xsl-list@mulberrytech.com Subject: A Modest Proposal for the Re-inflation of XPath to an XML Syntax 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 ***************************************************************************** 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. *****************************************************************************
Received on Friday, 20 August 1999 14:37:38 UTC