XML::X...torial(3pm)
๐ XML::XQL::Tutorial ๐
okay bestie, sit down, hydrate, because we are learning the XML Query Language today and honestly? it's giving main character energy. this page is XML::XQL::Tutorial(3pm), straight out of the User Contributed Perl Documentation collection, and it's literally just here to teach you the XQL query syntax. slay.
โจ NAME โจ
XML::XQL::Tutorial โ describes the XQL query syntax. that's it, that's the whole job description, and it ate. ๐
๐ธ DESCRIPTION ๐ธ
so this doc walks you through the basic features of the XML Query Language (XQL, for short, iykyk). a proposal for the XQL spec got submitted to the XSL Working Group back in September 1998 โ iconic, vintage, ahead of its time. you can find the spec at:
http://www.w3.org/TandS/QL/QL98/pp/xql.html
and here's the tea: it's only a proposal at this point, so things may change. but ngl, it's very likely the final version will be close to the proposal. also, full transparency, most of this document was copied straight from the spec โ so like, credit where credit is due. ๐ซถ
also also: go see the XML::XQL man page. it's the companion piece. besties fr.
๐ฆ INTRODUCTION ๐ฆ
XQL (XML Query Language) is a natural extension of the XSL pattern language, no cap. it takes everything XSL already does for identifying classes of nodes and just... levels it up โ adding Boolean logic, filters, indexing into collections of nodes, and more. it's giving glow-up. โจ
XQL is designed specifically for XML documents. it's a general purpose query language, which means one single syntax can be used for queries, addressing, and patterns. it's concise, simple, and powerful. the trifecta. ๐
and the way that it's designed to be used in so many contexts?? although it's a superset of XSL patterns, it's also applicable to providing links to nodes, for searching repositories, and for a whole bunch of other applications. versatile queen. ๐
ok small note bestie: the term XQL is a working term for the language described in this proposal. it is not their intent that this term be used permanently. also โ ๏ธ beware: another query language exists called XML-QL, and it uses a syntax very similar to SQL. do not get them mixed up, that would be so embarrassing. ๐
the XML::XQL module has added functionality on top of the XQL spec, and it's called XQL+. if you want only the XQL functionality as described in the spec, use the XML::XQL::Strict module instead. heads up though: the XQL spec makes a distinction between core XQL and XQL extensions, but this implementation makes no distinction โ so the Strict module therefore implements everything described in the XQL spec. see the XML::XQL man page for more info about the Strict module. and don't worry, this tutorial will clearly flag it every time we're talking about XQL+. ๐
๐ XQL Patterns ๐
this section is all about the core XQL notation. these features should be part of every XQL implementation, and they serve as the base level of functionality for its use in different technologies. the foundation, the blueprint, the starter pack. ๐ง
the basic syntax for XQL mimics the URI directory navigation syntax โ but instead of navigating through a physical file structure, you're navigating through elements in the XML tree. same vibe, different realm.
for example, this URI means find the foo.jpg file within the bar directory:
bar/foo.jpg
and similarly, in XQL, this means find the collection of fuz elements within baz elements:
baz/fuz
throughout this document you'll find numerous samples. they all refer to the data shown in the sample file at the end of this man page. keep it open, you'll need it. ๐
๐ Context ๐
a context is the set of nodes against which a query operates. for the entire query โ which gets passed to the XML::XQL::Query constructor through the Expr option โ the context is the list of input nodes that is passed to the query() method. that's the whole definition, bestie, no notes.
XQL lets a query choose between using the current context as the input context, or using the 'root context' as the input context. the 'root context' is a context containing only the root-most element of the document. when you're using XML::DOM, that's the Document object.
by default, a query uses the current context. a query prefixed with / (forward slash) uses the root context. and a query may optionally explicitly state that it's using the current context by using the ./ (dot, forward slash) prefix. both of these notations are analogous to the notations used to navigate directories in a file system โ see, it all comes back around. ๐
and the ./ prefix is only required in one situation, so pay attention: a query may use the // operator to indicate recursive descent. when this operator appears at the beginning of the query, the initial / causes the recursive descent to perform relative to the root of the document or repository. the prefix .// allows a query to perform a recursive descent relative to the current context. okay that's the whole rule, we move. ๐
Examples:
- find all
authorelements within the current context. since the period is really not used alone, this example forward-references other features:
./author
- note that this is equivalent to:
author
- find the root element (
bookstore) of this document:
/bookstore
- find all
authorelements anywhere within the current document:
//author
- find all books where the value of the
styleattribute on the book is equal to the value of thespecialtyattribute of thebookstoreelement at the root of the document:
book[/bookstore/@specialty = @style]
๐ธ Query Results ๐ธ
the collection returned by an XQL expression preserves document order, hierarchy, and identity, to the extent that these are defined. translation: a collection of elements will always be returned in document order without repeats. no duplicates, no chaos, we love a tidy queen. ๐
ok important caveat: the spec states that the order of attributes within an element is undefined โ but this implementation does keep attributes in document order. so like, technically a bonus. see the XML::XQL man page for more details regarding Document Order. ๐ซถ
๐ Collections - 'element' and '.' ๐
the collection of all elements with a certain tag name is expressed using the tag name itself. this can be qualified by showing that the elements are selected from the current context ./, but the current context is assumed and often need not be noted explicitly. it's the default, it's the vibe, it's the no-thought-needed option. โจ
Examples:
- find all
first-nameelements. these examples are equivalent:
./first-name
first-name
- find all unqualified
bookelements:
book
- find all
first.nameelements:
first.name
๐ Selecting children and descendants - '/' and '//' ๐
the collection of elements of a certain type can be determined using the path operators (/ or //). these operators take as their arguments a collection (left side) from which to query elements, and a collection indicating which elements to select (right side).
- the child operator (
/) selects from immediate children of the left-side collection. - the descendant operator (
//) selects from arbitrary descendants of the left-side collection.
in effect, the // can be thought of as a substitute for one or more levels of hierarchy. and lowkey, the path operators change the context as the query is performed โ so by stringing them together, users can 'drill down' into the document. drill, baby, drill. ๐ ๏ธ
Examples:
- find all
first-nameelements within anauthorelement. note that theauthorchildren of the current context are found, and thenfirst-namechildren are found relative to the context of theauthorelements:
author/first-name
- find all
titleelements, one or more levels deep in thebookstore(arbitrary descendants):
bookstore//title
- note that this is different from the following query, which finds all
titleelements that are grandchildren ofbookstoreelements:
bookstore/*/title
- find
emphelements anywhere insidebookexcerpts, anywhere inside thebookstore:
bookstore//book/excerpt//emph
- find all
titles, one or more levels deep in the current context. note that this situation is essentially the only one where the period notation is required:
.//title
โญ Collecting element children - '*' โญ
an element can be referenced without using its name by substituting the * collection. the * collection returns all elements that are children of the current context, regardless of their tag name. no name? no problem. ๐ซ
Examples:
- find all element children of
authorelements:
author/*
- find all
last-names that are grand-children ofbooks:
book/*/last-name
- find the grandchildren elements of the current context:
*/*
- find all elements with
specialtyattributes. note that this example uses subqueries, which are covered in Filters, and attributes, which are discussed in Finding an attribute:
*[@specialty]
๐ Finding an attribute - '@' ๐
attribute names are preceded by the @ symbol. XQL is designed to treat attributes and sub-elements impartially, and capabilities are equivalent between the two types wherever possible. equal treatment, we stan. โ๏ธ
โ ๏ธ note: attributes cannot contain subelements. thus, attributes cannot have path operators applied to them in a query. such expressions will result in a syntax error. also, the XQL spec states that attributes are inherently unordered and indices cannot be applied to them โ but this implementation allows it. so don't come for me when the spec disagrees with your working code. ๐
Examples:
- find the
styleattribute of the current element context:
@style
- find the
exchangeattribute onpriceelements within the current context:
price/@exchange
- the following example is not valid:
price/@exchange/total
- find all books with
styleattributes. note that this example uses subqueries, which are covered in Filters:
book[@style]
- find the
styleattribute for allbookelements:
book/@style
๐ฅ XQL Literals ๐ฅ
XQL query expressions may contain literal values (i.e. constants, the unchangeable babes).
- Numbers (integers and floats) get wrapped in
XML::XQL::Numberobjects. - Strings get wrapped in
XML::XQL::Textobjects. - Booleans (as returned by
true()andfalse()) get wrapped inXML::XQL::Booleanobjects.
strings must be enclosed in single or double quotes. and here's the catch: since XQL does not allow escaping of special characters, it's impossible to create a string with both a single and a double quote in it. ๐ญ to remedy this, XQL+ has added the q// and qq// string delimiters, which behave just like they do in Perl. thank u, Perl. ๐ซถ
for Numbers, exponential notation is not allowed. use the XQL+ function eval() to circumvent this problem. see the XML::XQL man page for details.
the empty list or undef is represented by [] (i.e. reference to empty array) in this implementation. iconic, minimal, empty-but-make-it-fashion. ๐
Example
- Integer Numbers:
234
-456
- Floating point Numbers:
1.23
-0.99
- Strings:
"some text with 'single' quotes"
'text with "double" quotes'
- Not allowed:
1.23E-4 (use eval("1.23E-4", "Number") in XQL+)
"can't use \"double \"quotes" (use q/can't use "double" quotes/ in XQL+)
๐ง Grouping - '()' ๐ง
parentheses can be used to group collection operators for clarity, or wherever the normal precedence is inadequate to express an operation. when in doubt, wrap it in parens, bestie. it's giving organized. ๐
Filters - '[]' ๐
Okay bestie, this is where XQL gets actually powerful. You can slap constraints and branching onto any collection by adding a filter clause [ ] to it. Think of it like the SQL WHERE clause, except it runs with ANY semantics. ๐
Inside the filter lives a whole lil query of its own, called the subquery. That subquery evaluates down to a Boolean, and it gets tested against every single element in the collection. Any element that fails the test? Gone. Omitted from the result collection, no notes, no goodbye text. ๐ญ
But here's the convenient part โ if you put a collection inside the filter instead of a Boolean, XQL does a little conversion for you: TRUE if the collection has any members at all, FALSE if it's empty. So an expression like author/degree is basically implying a collection-to-Boolean conversion function, like this mythical there-exists-a method:
author[.there-exists-a(degree)]
Also bestie, heads up: you can stack any number of filters at a given level of an expression. But empty filters are NOT allowed. Don't try it. ๐
Examples, because seeing it > hearing it:
- Find all books that contain at least one
excerptelement:
book[excerpt]
- Find all titles of books that contain at least one
excerptelement:
book[excerpt]/title
- Find all authors of books where the book contains at least one
excerpt, and the author has at least onedegree:
book[excerpt]/author[degree]
- Find all books that have authors with at least one
degree:
book[author/degree]
- Find all books that have an
excerptand atitle:
book[excerpt][title]
Any and all semantics - '$any$' and '$all$' โจ
You can explicitly say whether you want any-semantics or all-semantics using the $any$ and $all$ keywords. Main character energy: you decide. ๐
$any$โ flags that a condition holds true if any item in a set meets it.$all$โ means all elements in a set must meet the condition for it to hold true.
Both of these are keywords that show up before a subquery expression inside a filter. Placement matters, bestie.
Examples:
- Find all
authorelements where one of the last names is Bob:
author[last-name = 'Bob']
author[$any$ last-name = 'Bob']
- Find all
authorelements where none of thelast-nameelements are Bob:
author[$all$ last-name != 'Bob']
- Find all
authorelements where the first last name is Bob:
author[last-name[0] = 'Bob']
Indexing into a collection - '[]' and '$to$' ๐ฅ
XQL makes finding one specific node in a whole set of nodes so easy. Just wrap the index ordinal in square brackets. And yes, it's 0 based โ we start counting at zero in this house. ๐
You can also pull a range of elements. To do that, put an expression inside the subscript operator (the square brackets) instead of a single value. Those expressions can be a comma separated list of any of the following:
n Returns the nth element
-n Returns the element that is n-1 units from the last element.
E.g., -1 means the last element. -2 is the next to last element.
m $to$ n Returns elements m through n, inclusive
Examples:
- Find the first
authorelement:
author[0]
- Find the third
authorelement that has afirst-name:
author[first-name][2]
Real talk though โ indices are relative to the parent. So consider this data:
<x>
<y/>
<y/>
</x>
<x>
<y/>
<y/>
</x>
The following expression returns the first y from each of the x's:
x/y[0]
The following returns the first y from the entire set of y's within the x's:
(x/y)[0]
And the following returns the first y from the first x:
x[0]/y[0]
More examples, because we love a demo:
- Find the first and fourth
authorelements:
author[0,3]
- Find the first through fourth
authorelements:
author[0 $to$ 3]
- Find the first, the third through fifth, and the last
authorelements:
author[0, 2 $to$ 4, -1]
- Find the last
authorelement:
author[-1]
Boolean Expressions ๐ธ
Boolean expressions can be used inside subqueries. Like, one could use them to find all nodes of a particular value, or all nodes with nodes in particular ranges. The form is ${op}, where {op} can be any expression of the form {b|a} โ meaning the operator takes lvalue and rvalue arguments and returns a Boolean result. Math but make it cute. ๐ง
Note that the XQL Extensions section defines additional Boolean operations. Keep that in your back pocket.
Boolean AND and OR - '$and$' and '$or$' ๐
$and$ and $or$ are how you perform Boolean ands and ors. Simple as.
Pair the Boolean operators with grouping parentheses and you can build very sophisticated logical expressions. It's giving genius, honestly.
And good news: spaces are not significant โ you can leave them out, or keep them in for clarity like the examples show.
Examples:
- Find all
authorelements that contain at least onedegreeand oneaward.
author[degree $and$ award]
- Find all
authorelements that contain at least onedegreeorawardand at least onepublication.
author[(degree $or$ award) $and$ publication]
Boolean NOT - '$not$' ๐
$not$ is a Boolean operator that negates the value of an expression within a subquery. The hater of operators, respectfully.
Examples:
- Find all
authorelements that contain at least onedegreeelement and that contain nopublicationelements.
author[degree $and$ $not$ publication]
- Find all
authorelements that containpublicationelements but do not contain eitherdegreeelements orawardelements.
author[$not$ (degree $or$ award) $and$ publication]
Union and intersection - '$union$', '|' and '$intersect$' ๐ฆ
The $union$ operator (shortcut is |, iykyk) returns the combined set of values from the query on the left and the query on the right. Duplicates get filtered out. And the resulting list is sorted in document order. Chef's kiss. ๐
Note: because this is a union, the set returned may include 0 or more elements of each element type in the list. To restrict the returned set to nodes that contain at least one of each of the elements in the list, use a filter, as discussed in Filters.
The $intersect$ operator returns the set of elements in common between two sets.
Examples:
- Find all
first-names andlast-names:
first-name $union$ last-name
- Find all
books andmagazines from a bookstore:
bookstore/(book | magazine)
- Find all
books and allauthors:
book $union$ book/author
- Find the
first-names,last-names, ordegrees from authors within eitherbooks ormagazines:
(book $union$ magazine)/author/(first-name $union$ last-name $union$ degree)
- Find all
books withauthor/first-nameequal to'Bob'and allmagazines withpriceless than10:
book[author/first-name = 'Bob'] $union$ magazine[price $lt$ 10]
๐ Equivalence โ $eq$, =, $ne$ and !=
okay bestie so the = sign means equality, and != means inequality. and if the symbols aren't your vibe, you can literally just spell it out: $eq$ and $ne$ do equality and inequality too. same thing, different outfit ๐
For string delimiters in expressions you can use single quotes or double quotes. this is lowkey a big deal because it makes it way easier to construct and pass XQL from inside scripting languages โ no fighting with escaping, periodt.
so when you're comparing values of elements, the value() method is implied. like, last-name < 'foo' really means last-name!value() < 'foo'. the value() is just silently doing its thing in the background. โจ
๐ธ filters are always with respect to a context. so the expressionbook[author]means: for everybookelement that is found, see if it has anauthorsubelement. same energy withbook[author = 'Bob']โ for everybookelement found, see if it has a subelement namedauthorwhose value is'Bob'.
and you can check the value of the context itself using the . (period)! for example, book[. = 'Trenton'] means for every book that is found, see if its value is 'Trenton'. the context is the main character, obviously ๐
Examples:
Find all author elements whose last name is Bob:
author[last-name = 'Bob']
author[last-name $eq$ 'Bob']
Find all authors where the from attribute is not equal to 'Harvard':
degree[@from != 'Harvard']
degree[@from $ne$ 'Harvard']
Find all authors where the last-name is the same as the /guest/last-name element:
author[last-name = /guest/last-name]
Find all authors whose text is 'Matthew Bob':
author[. = 'Matthew Bob']
author = 'Matthew Bob'
๐ฅ Comparison โ <, <=, >, >=, $lt, $ilt$ etc.
a whole set of binary comparison operators is available for comparing numbers and strings, and they return Boolean results. so: $lt$, $le$, $gt$, $ge$ stand for less than, less than or equal, greater than, and greater than or equal. ๐
and bestie, these same operators come in a case insensitive form too: $ieq$, $ine$, $ilt$, $ile$, $igt$, $ige$. slay.
also <, <=, > and >= are allowed as short cuts for $lt$, $le$, $gt$ and $ge$. because typing is hard and we're all busy ๐
Examples:
Find all author elements whose last name is bob and whose price is > 50:
author[last-name = 'Bob' $and$ price $gt$ 50]
Find all authors where the from attribute is not equal to 'Harvard':
degree[@from != 'Harvard']
Find all authors whose last name begins with 'M' or greater:
author[last-name $ge$ 'M']
Find all authors whose last name begins with 'M', 'm' or greater:
author[last-name $ige$ 'M']
Find the first three books:
book[index() $le$ 2]
Find all authors who have more than 10 publications:
author[publications!count() $gt$ 10]
๐ XQL+ Match operators โ $match$, $no_match$, =~ and !~
XQL+ said "we can do pattern matching too" and honestly? iconic. ๐
the $match$ operator (shortcut is =~) returns TRUE if the lvalue matches the pattern described by the rvalue. and the $no_match$ operator (shortcut is !~) returns FALSE if they match. ๐ฆ
also, both the lvalue and rvalue get cast to strings first. no cap.
the rvalue string should have the syntax of a Perl rvalue โ that means the delimiters should be included and modifiers are allowed. and when you use delimiters other than slashes /, you gotta include the m. the rvalue should be a string, so don't forget the quotes! (or use the q// or qq// delimiters in XQL+, check the XML::XQL man page for that ๐ธ)
๐ heads up bestie: you can't use the Perl substitution operators///here. try using the XQL+subst()function instead!
Examples:
Find all authors whose name contains bob or Bob:
author[first-name =~ '/[Bb]ob/']
Find all book titles that don't contain 'Trenton' (case-insensitive):
book[title !~ 'm!trenton!i']
๐ง Oher XQL+ comparison operators โ $isa, $can$
see the XML::XQL man page for other operators available in XQL+. there's lore there, go read it ๐
๐ซถ Comparisons and vectors
the lvalue of a comparison can be a vector or a scalar. but the rvalue of a comparison must be a scalar, or a value that can be cast at runtime to a scalar. no exceptions, sorry bestie ๐
and if the lvalue of a comparison is a set, then any (exists) semantics are used for the comparison operators. meaning: the result of a comparison is true if any item in the set meets the condition. one of them just has to show up and slay โญ
โญ Comparisons and literals
the spec states that the lvalue of an expression cannot be a literal. so '1' = a is not allowed. ๐
this implementation allows it, but it's not clear how useful that is. (we're being honest with you, that's the whole vibe here.)
๐ Casting of literals during comparison
elements, attributes and other XML node types get casted to strings (Text) by applying the value() method. the value() method calls the text() method by default, but this behavior can be altered by the user, so value() may return other XQL data types. โจ
when two values are compared, they are first casted to the same type. see the XML::XQL man page for details on casting.
๐ธ and now for the messy part: the XQL spec is not very clear on how values should be casted for comparison. discussions with the authors of the XQL spec revealed that there was some disagreement and their implementations differed on this point. this implementation is closest to that of Joe Lapp from webMethods, Inc.
ngl that's the tea โ
๐
Methods - method() or query!method() ๐
Okay bestie, this is where XQL gets its main character energy. XQL makes a distinction between functions and methods. See the XML::XQL man page for details.
XQL provides methods for advanced manipulation of collections. These methods provide specialized collections of nodes (see Collection methods), as well as information about sets and nodes.
Methods are of the form method(arglist)
Consider the query book[author]. It will find all books that have authors. Formally, we call the book corresponding to a particular author the reference node for that author. That is, every author element that is examined is an author for one of the book elements. (See the Annotated XQL BNF Appendix for a much more thorough definition of reference node and other terms. See also the XML::XQL man page.) Methods always apply to the reference node โ that's the whole vibe, no cap.
For example, the text() method returns the text contained within a node, minus any structure. (That is, it is the concatenation of all text nodes contained with an element and its descendants.) The following expression will return all authors named 'Bob':
author[text() = 'Bob']
The following will return all authors containing a first-name child whose text is 'Bob':
author[first-name!text() = 'Bob']
The following will return all authors containing a child named Bob:
author[*!text() = 'Bob']
Method names are case sensitive. See the XML::XQL man page on how to define your own methods and functions.
๐ง Information methods
The following methods provide information about nodes in a collection. These methods return strings or numbers, and may be used in conjunction with comparison operators within subqueries.
Method: text()
The text() method concatenates text of the descendents of a node, normalizing white space along the way. White space will be preserved for a node if the node has the xml:space attribute set to 'preserve', or if the nearest ancestor with the xml:space attribute has the attribute set to 'preserve'. When white space is normalized, it is normalized across the entire string. Spaces are used to separate the text between nodes. When entity references are used in a document, spacing is not inserted around the entity refs when they are expanded.
In this implementation, the method may receive an optional parameter to indicate whether the text() of Element nodes should include the text() of its Element descendants. See XML::XQL man page for details.
Examples:
Find the authors whose last name is 'Bob':
author[last-name!text() = 'Bob']
Note this is equivalent to:
author[last-name = 'Bob']
Find the authors with value 'Matthew Bob':
author[text() = 'Matthew Bob']
author[. = 'Matthew Bob']
author = 'Matthew Bob'
Method: rawText()
The rawText() method is similar to the text() method, but it does not normalize whitespace. Fr fr, that's the only difference.
In this implementation, the method may receive an optional parameter to indicate whether the rawText() of Element nodes should include the rawText() of its Element descendants. See XML::XQL man page for details.
Method: value()
Returns a type cast version of the value of a node. If no data type is provided, returns the same as text().
Shortcuts ๐
For the purposes of comparison, value( ) is implied if omitted. In other words, when two items are compared, the comparison is between the value of the two items. Remember that in absence of type information, value() returns text().
The following examples are equivalent:
author[last-name!value() = 'Bob' $and$ first-name!value() = 'Joe']
author[last-name = 'Bob' $and$ first-name = 'Joe']
price[@intl!value() = 'canada']
price[@intl = 'canada']
Method: nodeType()
Returns a number to indicate the type of the node. The values were based on the node type values in the DOM:
element 1
attribute 2
text 3
entity 6 (not in XQL spec)
PI 7
comment 8
document 9
doc. fragment 10 (not in XQL spec)
notation 11 (not in XQL spec)
Heads up bestie: in XQL, CDATASection nodes and EntityReference nodes also return3, whereas in the DOM CDATASection returns4and EntityReference returns5. Use the XQL+ methodDOM_nodeType()to get DOM node type values. See theXML::DOMman page for node type values of nodes not mentioned here.
Method: nodeTypeString
Returns the name of the node type in lowercase or an empty string. The following node types are currently supported 1 (element), 2 (attribute), 3 (text), 7 (processing_instruction), 8 (comment), 9 (document)
Method: nodeName()
Returns the tag name for Element nodes and the attribute name of attributes. Short and sweet, we love that for her.
๐ Collection index methods
Method: index()
Returns the index of the value within the search context (i.e. with the input list of the subquery.) This is not necessarily the same as the index of a node within its parent node. Note that the XQL spec doesn't explain it well. (Not me defending the spec, it's just true.)
Examples:
Find the first 3 degrees:
degree[index() $lt$ 3]
Note that it skips over other nodes that may exist between the degree elements.
Consider the following data:
<x>
<y/>
<y/>
</x>
<x>
<y/>
<y/>
</x>
The following expression will return the first y from each x:
x/y[index() = 0]
This could also be accomplished by (see Indexing into a Collection):
x/y[0]
Method: end()
The end() method returns true for the last element in the search context. Again, the XQL spec does not explain it well. She's giving last-place-but-make-it-iconic.
Examples:
Find the last book:
book[end()]
Find the last author for each book:
book/author[end()]
Find the last author from the entire set of authors of books:
(book/author)[end()]
๐งฎ Aggregate methods
Method: count( [QUERY] )
Returns the number of values inside the search context. In XQL+, when the optional QUERY parameter is supplied, it returns the number of values returned by the QUERY. Math girlie behavior and we respect it. โจ
๐ Namespace methods
The following methods can be applied to a node to return namespace information.
Method: baseName()
Returns the local name portion of the node, excluding the prefix. Local names are defined only for element nodes and attribute nodes. The local name of an element node is the local portion of the node's element type name. The local name of an attribute node is the local portion of the node's attribute name. If a local name is not defined for the reference node, the method evaluates to the empty set.
Method: namespace()
Returns the URI for the namespace of the node. Namespace URIs are defined only for element nodes and attribute nodes. The namespace URI of an element node is the namespace URI associated with the node's element type name. The namespace URI of an attribute node is the namespace URI associated with the node's attribute name. If a namespace URI is not defined for the reference node, the method evaluates to the empty set.
Method: prefix()
Returns the prefix for the node. Namespace prefixes are defined only for element nodes and attribute nodes. The namespace prefix of an element node is the shortname for the namespace of the node's element type name. The namespace prefix of an attribute node is the shortname for the namespace of the node's attribute name. If a namespace prefix is not defined for the reference node, the method evaluates to the empty set.
The spec states: A node's namespace prefix may be defined within the query expression, within the document under query, or within both the query expression and the document under query. If it is defined in both places the prefixes may not agree. In this case, the prefix assigned by the query expression takes precedence. In this implementation you cannot define the namespace for a query, so this can never happen. (A conflict that literally cannot happen? We stan a chill implementation.)
Examples:
Find all unqualified book elements. Note that this does not return my:book elements:
book
Find all book elements with the prefix 'my'. Note that this query does not return unqualified book elements:
my:book
Find all book elements with a 'my' prefix that have an author subelement:
my:book[author]
Find all book elements with a 'my' prefix that have an author subelement with a my prefix:
my:book[my:author]
Find all elements with a prefix of 'my':
my:*
Find all book elements from any namespace:
*:book
Find any element from any namespace:
*
Find the style attribute with a 'my' prefix within a book element:
book/@my:style
All attributes of an element can be returned using @*. This is potentially useful for applications that treat attributes as fields in a record.
Examples:
Find all attributes of the current element context:
@*
Find style attributes from any namespace:
@*:style
Find all attributes from the 'my' namespace, including unqualified attributes on elements from the 'my' namespace:
@my:*
โจ Functions โจ
Okay bestie, this section is literally all about the functions of XQL. The spec says (and I quote, kinda): XQL defines two kinds of functions โ collection functions and pure functions. Collection functions use the search context of the Invocation instance, while pure functions ignore the search context, except to evaluate the function's parameters. A collection function evaluates to a subset of the search context, and a pure function evaluates to either a constant value or to a value that depends only on the function's parameters. ๐
Don't worry if you don't get it. Just use them! ๐
๐ Collection functions ๐
The collection functions give you access to the various types of nodes in a document. Any of these collections can be constrained and indexed. The collections return the set of children of the reference node meeting the particular restriction. ๐
๐ Function: textNode() ๐
The collection of text nodes. โจ
๐ Function: comment() ๐
The collection of comment nodes. ๐ฌ
๐ Function: pi() ๐
The collection of processing instruction nodes. ๐ง
๐ Function: element( [NAME] ) ๐
The collection of all element nodes. If the optional text parameter is provided, it only returns element children matching that particular name. ๐ท๏ธ
๐ Function: attribute( [NAME] ) ๐
The collection of all attribute nodes. If the optional text parameter is provided, it only returns attributes matching that particular name. ๐
๐ Function: node() ๐
The collection of all non-attribute nodes. ๐
Examples:
- Find the second text node in each
pelement in the current context:
p/textNode()[1]
- Find the second comment anywhere in the document. See Context for details on setting the context to the document root:
//comment()[1]
๐ธ Other XQL Functions ๐ธ
๐ Function: ancestor(QUERY) ๐
Finds the nearest ancestor matching the provided query. It returns either a single element result or an empty set []. Note that this node is never the reference node itself. ๐งฌ
Examples:
- Find the nearest
bookancestor of the current element:
ancestor(book)
- Find the nearest ancestor
authorelement that is contained in abookelement:
ancestor(book/author)
๐ Function: id(NAME) ๐
Pure function that evaluates to a set. The set contains an element node that has an 'id' attribute whose value is identical to the string that the Text parameter quotes. The element node may appear anywhere within the document under query. If more than one element node meets these criteria, the function evaluates to a set that contains the first node appearing in a document ordering of the nodes. ๐
๐ Function: true() and false() ๐
Pure functions that each evaluate to a Boolean. true() evaluates to 'true', and false() evaluates to 'false'. These functions are useful in expressions that are constructed using entity references or variable substitution, since they may replace an expression found in an instance of Subquery without violating the syntax required by the instance of Subquery. They return an object of type XML::XQL::Boolean. โ
โ
๐ Function: date(QUERY) ๐
date is a pure function that typecasts the value of its parameter to a set of dates. If the parameter matches a single string, the value of the function is a set containing a single date. If the parameter matches a QUERY, the value of the function is a set of dates, where the set contains one date for each member of the set to which the parameter evaluates. ๐
XQL does not define the representation of the date value, nor does it define how the function translates parameter values into dates. This implementation uses the Date::Manip module to parse dates, which accepts almost any imaginable format. See XML::XQL to plug in your own Date implementation. ๐๏ธ
Include the XML::XQL::Date package to add the XQL date type and the date() function, like this:
use XML::XQL::Date;
๐ Perl builtin functions and other XQL+ functions ๐
XQL+ provides XQL function wrappers for most Perl builtin functions. It also provides other cool functions like subst(), map(), and eval() that allow you to modify documents and embed perl code. If this is still not enough, you can add your own function and methods. See XML::XQL man page for details. ๐ ๏ธ
๐ Sequence Operators - ';' and ';;' ๐
The whitepaper 'The Design of XQL' by Jonathan Robie, which can be found at <http://www.texcel.no/whitepapers/xql-design.html> describes the sequence operators ';;' (precedes) and ';' (immediately precedes.) Although these operators are not included in the XQL spec, I thought I'd add them anyway. ๐
๐ Immediately Precedes - ';' ๐
Example:
With the following input:
<TABLE>
<ROWS>
<TR>
<TD>Shady Grove</TD>
<TD>Aeolian</TD>
</TR>
<TR>
<TD>Over the River, Charlie</TD>
<TD>Dorian</TD>
</TR>
</ROWS>
</TABLE>
Find the TD node that contains "Shady Grove" and the TD node that immediately follows it:
//(TD="Shady Grove" ; TD)
Note that inXML::DOMthere is actually a text node with whitespace between the twoTDnodes, but those are ignored by this operator, unless the text node has'xml:space'set to'preserve'. See ??? for details. ๐ค
๐ Precedes - ';;' ๐
Example:
With the following input (from Hamlet):
<SPEECH>
<SPEAKER>MARCELLUS</SPEAKER>
<LINE>Tis gone!</LINE>
<STAGEDIR>Exit Ghost</STAGEDIR>
<LINE>We do it wrong, being so majestical,</LINE>
<LINE>To offer it the show of violence;</LINE>
<LINE>For it is, as the air, invulnerable,</LINE>
<LINE>And our vain blows malicious mockery.</LINE>
</SPEECH>
Return the STAGEDIR and all the LINEs that follow it:
SPEECH//( STAGEDIR ;; LINE )
Suppose an actor playing the ghost wants to know when to exit; that is, he wants to know who says what line just before he is supposed to exit. The line immediately precedes the stagedir, but the speaker may occur at any time before the line. In this query, we will use the "precedes" operator (";;") to identify a speaker that precedes the line somewhere within a speech. Our ghost can find the required information with the following query, which selects the speaker, the line, and the stagedir:
SPEECH//( SPEAKER ;; LINE ; STAGEDIR="Exit Ghost")
๐ Operator Precedence ๐
The following table lists operators in precedence order, highest precedence first, where operators of a given row have the same precedence. The table also lists the associated productions:
Production Operator(s)
---------- -----------
Grouping ( )
Filter [ ]
Subscript [ ]
Bang !
Path / //
Match $match$ $no_match$ =~ !~ (XQL+ only)
Comparison = != < <= > >= $eq$ $ne$ $lt$ $le$ $gt$
$ge$ $ieq$ $ine$ $ilt$ $ile$ $igt$ $ige$
Intersection $intersect$
Union $union$ |
Negation $not$
Conjunction $and$
Disjunction $or$
Sequence ; ;;
๐ Sample XML Document - bookstore.xml ๐
This file is also stored in samples/bookstore.xml that comes with the XML::XQL distribution.
<?xml version='1.0'?>
<!-- This file represents a fragment of a book store inventory database -->
<bookstore specialty='novel'>
<book style='autobiography'>
<title>Seven Years in Trenton</title>
<author>
<first-name>Joe</first-name>
<last-name>Bob</last-name>
<award>Trenton Literary Review Honorable Mention</award>
</author>
<price>12</price>
</book>
<book style='textbook'>
<title>History of Trenton</title>
<author>
<first-name>Mary</first-name>
<last-name>Bob</last-name>
<publication>
Selected Short Stories of
<first-name>Mary</first-name> <last-name>Bob</last-name>
</publication>
</author>
<price>55</price>
</book>
<magazine style='glossy' frequency='monthly'>
<title>Tracking Trenton</title>
<price>2.50</price>
<subscription price='24' per='year'/>
</magazine>
<book style='novel' id='myfave'>
<title>Trenton Today, Trenton Tomorrow</title>
<author>
<first-name>Toni</first-name>
<last-name>Bob</last-name>
<degree from='Trenton U'>B.A.</degree>
<degree from='Harvard'>Ph.D.</degree>
<award>Pulizer</award>
<publication>Still in Trenton</publication>
<publication>Trenton Forever</publication>
</author>
<price intl='canada' exchange='0.7'>6.50</price>
<excerpt>
<p>It was a dark and stormy night.</p>
<p>But then all nights in Trenton seem dark and
stormy to someone who has gone through what
<emph>I</emph> have.</p>
<definition-list>
<term>Trenton</term>
<definition>misery</definition>
</definition-list>
</excerpt>
</book>
<my:book style='leather' price='29.50' xmlns:my='http://www.placeholder-name-here.com/schema/'>
<my:title>Who's Who in Trenton</my:title>
<my:author>Robert Bob</my:author>
</my:book>
</bookstore>
๐ SEE ALSO ๐
The Japanese version of this document can be found on-line at <http://member.nifty.ne.jp/hippo2000/perltips/xml/xql/tutorial.htm>
XML::XQL, XML::XQL::Date, XML::XQL::Query and XML::XQL::DOM
That's a wrap, bestie! This manual page is fromperl v5.36.0, dated2022-12-06, and it's theXML::X...torial(3pm)page. Stay iconic! ๐โจ
๐ฆ where this page comes from
- debian bookworm: libxml-xql-perl 0.68-9 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- debian trixie: libxml-xql-perl 0.68-9 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu noble: libxml-xql-perl 0.68-9 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu resolute: libxml-xql-perl 0.68-9 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libxml-xql-perl 0.68-9 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms