
| [Up] |
![]() | Work in progressThis version may be updated without notice. |
Copyright © INRIA
XCL is one of the core modules of the technology.
XCL provides a set of tags that covers many useful features :
This module is just a convenient toolkit that covers most of useful general-purpose features, but does not intend to cover specific processes. Users should define their own module with EXP when they have to use made-to-measure dedicated processes.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
Note that for reasons of style, these words are not capitalized in this document.
The following specifications are part of the technologies.
1.1 Controling execution2 XML oriented actions
1.2 Assigning datas
1.3 Organizing processes
1.4 Sorting
2.1 Dealing with SAX and DOM3 Active Update
4.1 Connecting filters5 Fallback processing and definition
4.2 Rules
4.3 Channels
4.4 Filter definitions
4.5 Built-in filters
6.1 Elements
6.2 Foreign attributes
6.3 Predefined properties
6.4 Extended XPath functions
6.5 Data types
A Glossary
B Related specifications
C Lists
C.1 Examples listD for XCL
XCL provides instructions common to most imperative language to control the execution, assign datas, or organize processes.
As in many languages, XCL provides instructions to perform tests and loops :
Many active tags cause the creation of a property in the data set. Usually, the @name attribute specifies the name of the property to create ; if missing, the property is set as the current object.
Such active tags are, for example :
The active tags above are also performing tasks to accomplish what they are intending for. To simply assign a value to a property without performing additional tasks, XCL provides the <xcl:set> element. <xcl:set> can be used for simple assignment as well as for computations, for object browsing with XPath, or for building lists, maps, XML fragments, or even a mix of these structures.
The <xcl:set> element may host the @value attribute to perform simple assignments :
<xcl:set name="who" value="Bill"/>
<xcl:set name="welcome" value="Hello { $who } !"/>
To create new properties in the data set...
<xcl:set value="Bill"/>
<xcl:set value="Hello { . } !"/>
...to set a new value to the current object.
XPath can be used to perform computations :
<xcl:set name="pi" value="{ number( '3.1415' ) }"/>
<xcl:set name="total" value="{ $price * $qty }"/>
<xcl:set name="files" value="{ count( $files ) }"/>
... to cross XML nodes :
<xcl:set name="total" value="{ orders/order[ @confirmed ]/@total }"/>
... to cross X-operable objects :
<xcl:set name="files" value="{ io:file( '/path/to/dir' )//*[@io:is-file] }"/>
In , a composite value consists on a collection of named or unamed items. When the @value attribute of the <xcl:set> element is omitted, each item may be specified within the content with the <xcl:item> element. The <xcl:item> may have itself a @value and a @name attributes.
In fact, if the @value attribute is not specified in the <xcl:set> or in the <xcl:item> elements, the content is performed ; the items of the context are used as the values to set.
<xcl:set name="who">
<xcl:item name="firstname" value="John"/>
<xcl:item name="lastname" value="Doe"/>
</xcl:set>
<xcl:set name="welcome" value="Hello { $who/firstname } { $who/lastname } !"/>
<xcl:set name="tasks">
<xcl:item value="open"/>
<xcl:item value="remove"/>
</xcl:set>
<xcl:set name="todo" value="Before : { $tasks/*[1] } ; after : { $tasks/*[2] }"/>
<xcl:set name="files">
<xcl:item name="toDelete">
<xcl:item value="{ io:file( '/path/to/file1' ) }"/>
<xcl:item value="{ io:file( '/path/to/file2' ) }"/>
</xcl:item>
<xcl:item name="toCreate">
<xcl:item value="{ io:file( '/path/to/file3' ) }"/>
<xcl:item value="{ io:file( '/path/to/file4' ) }"/>
</xcl:item>
</xcl:set>
Instead of named or unamed items, the content may be a snippet XML structure :
<xcl:set name="who">
<firstname>John</firstname>
<lastname>Doe</lastname>
</xcl:set>
<xcl:set name="welcome"
value="Hello { $who/firstname/text() } { $who/lastname/text() } !"/>
Items or other content may also be set conditionally :
<xcl:set name="files">
<xcl:item name="toDelete" xcl:if="{ $validate='yes' }">
<xcl:item value="{ io:file( '/path/to/file1' ) }"/>
<xcl:item value="{ io:file( '/path/to/file2' ) }"/>
</xcl:item>
<xcl:item name="toCreate">
<xcl:item value="{ io:file( '/path/to/file3' ) }"/>
<xcl:item value="{ io:file( '/path/to/file4' ) }"/>
</xcl:item>
</xcl:set>
<xcl:set name="who">
<xcl:if test="{ $gender='male' }">
<xcl:then>
<firstname>John</firstname>
</xcl:then>
<xcl:else>
<firstname>Jane</firstname>
</xcl:else>
</xcl:if>
<lastname>Doe</lastname>
</xcl:set>
<xcl:set name="welcome"
value="Hello { $who/firstname/text() } { $who/lastname/text() } !"/>
Most active tags that are creating a new property define also the @scope attribute that indicates which is the scope of the property to create. The values are shared, global, or local.
local is usually the default scope.
Some active tags accept parameters to tune their behaviour. For this purpose, they open a context, run their subactions, and use each item found in the context as parameters. To set a parameter in the context, use the <xcl:param> element.
For example, a stylesheet may accept parameters :
<xcl:transform output="/path/to/doc.html" source="/path/to/doc.xml"
stylesheet="/path/to/stylesheet.xsl"> <xcl:param name="date" value="{ $date }"/> <xcl:param name="page" value="1"/> </xcl:transform>
For example, when storing a file to an XML Native Database through XML:DB, the type of the resource must be specified :
<io:file name="myFile" uri="xmldb:provider://user:pwd@host:port/path/to/resource">
<xcl:param name="xmldb-resource-type" value="XMLResource"/>
</io:file>
<io:save content="..." uri="{ $myFile }"/>
The <xcl:active-sheet> element is usually the root element of an , but for specific purposes, some other elements are also suitable, such as <web:service> and <exp:module>. The root element of an may be any litteral element (that is to say an element that is not active).
Within an or an , the <xcl:logic> element may be used to organize callable unit processes ; its @name attribute defines the name of each logic procedure. Only one logic procedure may omit this attribute, which makes it the default. The (or ) itself is designated as the main logic procedure.
To call a logic procedure, the <xcl:call> element can be used ; the data set inside the called logic procedure keeps the shared and global properties, but its local properties are empty, unless otherwise parameters are explicitely passed with the <xcl:param> element. At the end of the execution of the called procedure, the process goes on after the caller action. If local properties of the data set in use by the called logic procedure must be kept, each must be explicitely specify with the <xcl:keep> element. All other local properties are lost.
[TODO: an example]Sorting is a feature strongly related to types of data, when they required a total ordering on some set of objects. covers many data-type issues in several specifications :
These methods always deal with typed data ; a data is always typed in ; the default type is #xs:string. However, some objects are not necessary comparable with others, which makes sorting results somewhat hazardous. Comparable objects are sorted according to the comparator function bound to their type. allow to specify which comparator function to bind to user define types, and also indicates how to compare 2 objects of different types ; this last points makes sorting a context-sensitive feature : 2 applications might choose to bind different comparator functions to a type ; please refer to the chapter about "integration with EXP" for more information.
The type of a data is defined :
The xcl:sort() function allow to sort a list of items regarding one or more type-aware sorting criteria. The xcl:reverse() function can reverse the sorting order of each criterion (that is to say in descendant order). This function can also be used out of the context of the sort function ; in this case, it reverses the order of the items in a collection.
| Sorting XML datas after infoset augmentation | |
|---|---|
In this example, a weather report indicates town temperatures expressed in °C as well as in °F. The type of the @temp attribute is those defined in another example. <weather-report> <town date="2005/09/09" name="Paris" temp="21°C"/> <town date="2005/09/08" name="Paris" temp="22°C"/> <town date="2005/09/09" name="Vladivostok" temp="32°F"/> <town date="2005/09/07" name="Paris" temp="20°C"/> <town date="2005/09/08" name="London" temp="23°C"/> </weather-report> The following snippet code simply parses the XML file, and validate it with the schema within which the expected type is defined ; then the towns are displayed in temperature order thanks to the xcl:sort() function :
<xcl:parse name="wr" source="file:///path/to/weather-report.xml"/>
<asl:validate augment="yes" node="{ $wr }" schema="file:///path/to/schema.asl"/>
<xcl:for-each name="town" select="{ xcl:sort( $wr/weather-report/town, @temp ) }">
<xcl:echo value="{ $town/@temp } { $town/@name } { $town/@date }"/>
</xcl:for-each>
Output : 32°F Vladivostok 2005/09/09 20°C Paris 2005/09/07 21°C Paris 2005/09/09 22°C Paris 2005/09/08 23°C London 2005/09/08 As expected, 32°F is placed before 20°C. If the @augment attribute of the <asl:validate> element was set to no, the temperatures will be sorted in lexical order, so 32°F would be placed at the last position. To force a lexical order on the augmented infoset, it is also possible to wrap the sort criterion with the string() function : string( @temp ). | |
Actions related to XML include :
Schema validation is provided while parsing with the @validate attribute of the <xcl:parse> element or with the <asl:validate> element.
[TODO]In most cases, handles XML documents without specifying if the underlying API is DOM or SAX ; however, it may be advantageous to prefer one or the other technique in certain cases, in particular when performances are critical : SAX may be more suitable because it allow to connect components in a pipeline fashion. Moreover, DOM trees are fully accessible with XPath expressions, whereas SAX events are not suitable to XPath because in XPath expressions are used both upon XML datas and non-XML datas compliant with XML, known as cross-operable objects. Thus, SAX documents may be preferred to DOM documents by applications that don't need to access to the content with XPath.
For example, Web applications built with pipelines serve dynamic pages faster, like shown in the example below :
| 3-tiers Web application with a SAX pipeline | |
|---|---|
In this example, the tiers involved are an XML native database, the Web front that hosts the below, and the browser, that will start to display the result whereas the XML native database still computes the request :
<web:mapping match="..." method="GET">
<io:request connect="xmldb:provider://user:pwd@host:port" name="results" output-type="SAX"We assume in this example that the XML native database will return several XML results that we want to merge and transform to a single HTML output.
| |
In fact, although hides the API involved in most usage, processing SAX events is not exactly the same than processing DOM trees. As explained in the example above, SAX events are deferred actions : when an XML document is of the type SAX, it is not really created ; a SAX handler that represent it is available for the actions that follows, and may be used to be connected to a component that will consume the document ; the inner actions will be processed only when the document will be consumed. This makes the sequence of actions somewhat disrupted. Actions made for SAX processing can't be safely switched to actions that are dealing with DOM.
| DOM or SAX ? | |||
|---|---|---|---|
The following example show two snippet s that are almost the same (they only differ by the @type attribute of the <xcl:document> element), but will produce two different XML documents :
| |||
Moreover, the litteral elements that may appear within a SAX <xcl:document> are also deferred : that is to say that here again the sequence is disrupted to avoid caching all the datas when attribute definitions or namespace declarations are encountered, because even if they can be defined anywhere in the content of the litteral element, they have to be applied on it. Actually, the content of a litteral element is performed but not recursively for each other litteral elements encountered inside ; thus, the events will be fired once the content performed without forgetting attribute definitions neither namespace declarations. Nested litteral elements will be processed in the same way when corresponding events have to be fired. In a global view, the processing sequence is performed level by level instead of in tree order.
Of course, this also applies on elements produced with the <xcl:element> action.
[FIXME: I really don't know if it is the good strategy for processing SAX ; events could be fired as soon as the first content is encountered, next attributes encountered would be errors.]is based on XPath to access datas, and it is not obvious to use XPath with SAX when several XPath expressions are involved sequentially : how to get an element that has been already consumed by a previous action ? Using a DOM fragment feeds with SAX events may help significantly : DOM act as a data aggregator, as a container that retain the datas needed for XPath extractions.
The <xcl:document> element is useful for this purpose :
<xcl:parse name="saxHandler" source="/path/to/my/file.xml" type="SAX"/>
<!-- ... -->
<xcl:document type="DOM">
{ $saxHandler }
</xcl:document>
...but it may be used to fire SAX events from a DOM source :
<xcl:parse name="domTree" source="/path/to/my/file.xml" type="DOM"/>
<!-- ... -->
<xcl:document type="SAX">
{ $domTree }
</xcl:document>
In fact, any mix of SAX and DOM may be merged in a single SAX or DOM document. Moreover, the resulting XML may also contain custom elements :
<xcl:parse name="saxHandler" source="/path/to/John-items.xml" type="SAX"/>
<xcl:parse name="domTree" source="/path/to/customers.xml" type="DOM"/>
<!-- ... -->
<xcl:document type="SAX">
<!-- type="DOM" works similarly -->
<purchaseOrder>
{ $saxHandler }
<billTo>
{ $domTree//customer[@name="John"] }
</billTo>
</purchaseOrder>
</xcl:document>
<xcl:document> is also suitable when an XML source is not intend to produce a well-formed XML document with a single root element. For example, a data source may produce text data around the root element(s), which is forbidden in pure XML ; it is easy with to complete such XML datas with a host root, giving a fully conformed XML document, as shown below :
<xcl:parse name="xmlDatas" source="/path/to/my/file.xml"/>
<!-- ... -->
<xcl:document type="SAX">
<!-- type="DOM" works similarly -->
<root>
{ $xmlDatas }
</root>
</xcl:document>
|
The content of the file : <?xml version="1.0" encoding="iso-8859-1"?> |
is a feature of that allows to update XML objects and X-operable objects with a set of basic operations. XCL implements with a set of advanced operations, more convenient to use than basic operations.
Some operations denotes that the object referred (called the referent) is part of a collection for which ordering may be important, or not ; for example, XML elements are such objects. When specified, the referent may be an integer that denotes the position of the object referred within the collection it belongs. The first item in a collection is at the position 1.

Some objects may be hierarchically linked to another object that it depends, called its parent. It is itself one of its children. Some operations on such objects may require to specify explicitely the parent of the referent when it is involved, others don't need to.
When specified, an operand is needed to perform a specific operation.
If the referent computed at runtime gives nothing, the operation fails without trying to resolve other datas (parent, operand, and inner actions).
In the list below, the referent, the parent and the operand (if any) are given respectively by the @referent, @parent, and @operand attributes. If an operand is expected and the @operand attribute is missing, the content of the X-operations will be performed ; when done, the operand will be the current object.

Notice that some operation act on the referent object itself (rename), others on its children (append), and other on the children of its parent (insert after).
The mapping between basic actions and the X-operations listed above is implied, according to the X-operable object and its characteristics :
An X-operation is only an XML way to apply basic actions.

An X-operable objects, may define restrictions on basic operations.
When used alone, an operation is applied when encountered at runtime. However, a set of operations may be grouped together in the aim of being applied or cancelled on user request. When this feature is used, the operations encountered are deferred operations. For this purpose, XCL provides the <xcl:commit> and <xcl:rollback> actions. The <xcl:operations> action is used to define the boundaries of a set of nested operations to defer.
A deferred operation must resolve its referent, parent and operand as soon as it is encountered. When applied, it must not resolve them again.

This facility has been introduced to ease the usage of XUpdate-like operations on XML objects when incompatible updates are encountered : for example, if the first element of a node set must be removed and the second one must be updated, the expected result won't be obtained because once the first element will be removed, the second will become the first and the third the second ; this is the one that will be updated.
A set of deferred operations act like if the XML document were frozen during the updates operations that are really applied later.
If not specified, a set of deferred operations is applied automatically at the end of its execution.
XCL defines a set of tags for applying XPath-based filters on XML entries (DOM or SAX) and plain-text streams.
A filter reads entirely one or several inputs, and can produce several outputs. Unlike XSLT, an XCL filter traverses each input tree in its natural order only. More complex processes that require deep structure transformations should be considered with XSLT. XCL filters are suitable when processes are localized on independant chunks of datas, which is advantageous for stream-processing of large inputs, although XCL filters can be also convenient for traversing automatically a DOM tree. By combining other active tags with the small set defined here, it is yet possible to achieve efficient pipeline processes.
An XCL filter act on the XPath data model of the inputs, whatever the style of reading (events or tree). Thus, everything read is presented to the filter as an XML node. The results produced have the same infoset whatever the style of reading, except if side effects due to deferring process occurs, as shown previously. The nature of the output is the same as the input, except if it is explicitely changed by using actions such as <xcl:document> that can produce a tree or events at user option. When several inputs are merged to a single output, the first data forwarded to the output determine the nature of the output.
An XCL filter is defined thanks to the <xcl:filter> element, which contains a set of ordered rules (<xcl:rule>). Within a rule, it is possible :
According to the attributes used with, the <xcl:filter> element can be used :
A filter can be both an inline filter definition and be connected to an input. External filters can be parsed thanks to the <xcl:parse-filter> element, that can also parse built-in filters.
Filters can be connected in a pipeline where the output of a filter becomes the input of a next filter. The first filter can be connected to an XML parser (or another XML producer), and the last to an XSLT transformer (or another XML consumer) :
<xcl:parse name="input" output-type="event" source="file:///path/to/file.xml"/>
<xcl:filter name="step1" source="{ $input }">
<!--some rules to apply here-->
</xcl:filter>
<xcl:filter name="step2" source="{ $step1 }">
<!--some rules to apply here-->
</xcl:filter>
<xcl:filter name="step3" source="{ $step2 }">
<!--some rules to apply here-->
</xcl:filter>
<xcl:transform output="file:///path/to/result.xml" source="{ $step3 }"/>...or "anonymously" :
<xcl:parse output-type="event" source="file:///path/to/file.xml"/>
<xcl:filter>
<!--some rules to apply here-->
</xcl:filter>
<xcl:filter>
<!--some rules to apply here-->
</xcl:filter>
<xcl:filter>
<!--some rules to apply here-->
</xcl:filter>
<xcl:transform output="file:///path/to/result.xml"/>Of course, XSLT transformers can also act as filters.
A filter appears as a set of ordered rules that can match nodes either on XPath patterns, or regular expressions. Once a rule matched, it is applied. A rule processes the node and its content separately : usually, the user act on the node before forwarding it to the next step, which cause the filter reading its content. A default rule is defined in order to match any node that weren't matched by the filter designed by the user :
<xcl:filter name="..." source="...">
<xcl:rule pattern="/ | node()">
<xcl:forward>
<xcl:apply-rules/>
</xcl:forward>
</xcl:rule>
</xcl:filter>This rule means that the node matched is forwarded as-is to the next step. Its content will be processed by the filter to look for a candidate rule. Thus, a minimal user-defined filter like this :
<xcl:filter name="..." source="..."/>...consist on reading its input and forward it as-is to the next step, because the only rule defined is the default rule which is appliable on each node of the input. The default rule is always the last rule applied if none matched, and users don't have to define this default rule. Designing a filter is easy because every node that is not explicitely matched is forwarded ; users just need to focus on what have to be changed while processing the pipeline.
The XPath patterns allowed in a rule definition are those defined in XSLT minus the key function which is dedicated to XSLT. According to the nature of the entry processed (DOM or SAX), they must be fully supported (case of DOM) or partially supported (case of SAX) by the underlying implementation. Actually, matching SAX events with XPath patterns may require to cache some datas expected to evaluate the pattern ; in order to keep the advantage of a streaming strategy, the cache must be as small as possible. A pattern that would require the entire entry to be cached would break the advantage of streaming, and a DOM-based strategy would be more suitable. Considering the pros and cons of caching capabilities, an implementation is free to restrict the usage of XPath patterns to a subset. Out of this subset, XPath patterns are considered unpredictable.
When a node matches a rule, the current object is set to the node that matched. When several rules are matching, those that has the higher priority is selected. The priority is computed in the same way than XSLT patterns, but it can also be specified explicitely.
The <xcl:apply-rules> element sends the matched node (that could have been modified) to the next step, and applies the current filter to its content. The next step is specified by the <xcl:forward> element, which can be :
If an <xcl:apply-rules> element is encountered outside a <xcl:forward> element, the node is ignored, but its content is applied on the filter.
If no <xcl:apply-rules> element is found inside a rule, the node and its content are ignored.
If more than one <xcl:apply-rules> elements are found while running a rule, the first is applied, the others are doing nothing.
Within a rule and a <xcl:forward> element, any active tags or litteral are allowed. XML litterals within the <xcl:forward> element are changing the structure of the output document.
<xcl:rule pattern="foo"> <xcl:forward> <xcl:apply-rules/> </xcl:forward> </xcl:rule>
<xcl:rule pattern="foo"/><xcl:rule pattern="foo"> <xcl:apply-rules/> </xcl:rule>
<xcl:rule pattern="foo"> <xcl:forward> <xcl:apply-rules/> </xcl:forward> </xcl:rule> <xcl:rule pattern="foo/node()"/>
As the name of the element to forward is known :
<xcl:rule pattern="foo"> <xcl:forward> <foo/> </xcl:forward> </xcl:rule>
But it is slightly different because the incoming element might have attributes whereas the element forwarded has none.
<xcl:rule pattern="foo"> <xcl:forward> <before> <!--some content--> </before> <xcl:apply-rules/> <after> <!--some content--> </after> </xcl:forward> </xcl:rule>
<xcl:rule pattern="foo"> <xcl:forward> <before> <!--some content--> </before> </xcl:forward> <xcl:apply-rules/> <xcl:forward> <after> <!--some content--> </after> </xcl:forward> </xcl:rule>
<xcl:rule pattern="foo"> <xcl:forward> <container> <xcl:apply-rules/> </container> </xcl:forward> </xcl:rule>
<xcl:rule pattern="foo"> <xcl:forward> <!--we assume that the file name is inside an attribute : <foo file="[some-file-name]"> --> <xcl:parse name="other" output-type="SAX" source="file:///path/to/{ @file }.xml"/> { $other } <xcl:apply-rules/> </xcl:forward> </xcl:rule>
<xcl:rule pattern="foo"> <xcl:rename operand="bar" referent="{ . }"/> <xcl:forward> <xcl:apply-rules/> </xcl:forward> </xcl:rule>
<xcl:rule pattern="foo"> <!--add 2 attributes--> <xcl:attribute name="new1" referent="{ . }" value="foo"/> <xcl:append referent="{ . }"> <xcl:attribute name="new2" value="foo"/> </xcl:append> <!--remove an attribute--> <xcl:remove parent="{ . }" referent="{ @attrToRemove }"/> <!--rename an attribute--> <xcl:rename operand="newName" referent="{ @attrToRename }"/> <!--change the value of an attribute--> <xcl:attribute name="attrToChange" referent="{ . }" value="newValue"/> <xcl:forward> <xcl:apply-rules/> </xcl:forward> </xcl:rule>
<xcl:rule pattern="removeAllAttr"> <xcl:remove parent="{ . }" referent="{ @* }"/> <xcl:forward> <xcl:apply-rules/> </xcl:forward> </xcl:rule>
Channels allow routing an XML output to an XML input. By connecting filters, a main transparent channel from one to one is used, but additive channels can be defined in order to dispatch the same input to several outputs.
A channel can be global or local.
Each channel should be connected to a consumer or to a pipeline connected to a consumer before connecting the main channel to a consumer or to a pipeline connected to a consumer. A disconnected channel would cache its entry which is not desirable in a streaming strategy, but acceptable for tree-based processes.
Channels can be specified as an output of a filter thanks to the @channel attribute of the <xcl:forward> element :
<xcl:rule pattern="foo"> <xcl:forward channel="c1 c2 c3"> <xcl:apply-rules/> </xcl:forward> </xcl:rule>
...which denotes that the XML datas have to be forwarded to the channels named "c1", "c2", and "c3" which are qualified names.
To connect channels to other filters or consumers, the xcl:channel() function must be used.
| A filter that separates elements | |
|---|---|
This example shows how to separate elements that are in a given namespace in a separate XML stream which is serialized to a file. <xcl:parse name="input" output-type="SAX" source="file:///path/to/file.xml"/> <xcl:filter name="step" source="{ $input }"> <xcl:rule pattern="acme:*" xmlns:acme="urn:acme-business-model"> <xcl:forward channel="acme"> <xcl:apply-rules/> </xcl:forward> </xcl:rule> </xcl:filter> <xcl:transform output="file:///path/to/acme-result.xml" source="{ xcl:channel('acme') }"/> <xcl:transform output="file:///path/to/other-result.xml" source="{ $step }"/> Of course, the channel consumed by the <xcl:transform> element could also be the source of a next filter. Notice that the second channel is connected to its consumer before the main channel. In an event-based process, this is the main channel that drives the pipeline : the pipeline is inactive until the last step is connected to a consumer. | |
Channels can be also be local to a rule.
Merging channels is the same as merging XML :
<!-- ... -->
<xcl:document type="SAX">
<root>
{ xcl:channel( 'c1' ) }
{ xcl:channel( 'c2' ) }
{ xcl:channel( 'c3' ) }
</root>
</xcl:document>2 predefined channels can be used :
Filters that intend to be reused can be defined outside the active sheets that are using them. For this purpose, the same element (<xcl:filter>) can be used as the root of the XML filter, but as it stands for a definition, it is not connected to a source : it is defined without the @source and @name attributes.
<?xml version="1.0" encoding="iso-8859-1"?>
<!--A standalone filter definition--> <xcl:filter xmlns:xcl="http://ns.inria.org/active-tags/xcl"> <!--some rules to apply here--> </xcl:filter>
Within the active sheet that will refer to that reusable filter, the <xcl:filter> element must be used with the @filter attribute :
<xcl:parse name="input" output-type="event" source="file:///path/to/file.xml"/> <xcl:filter filter="file:///path/to/myFilter.xcl" name="step" source="{ $input }"/> <xcl:transform output="file:///path/to/result.xml" source="{ $step }"/>
It is also possible to parse a filter and to connect it later :
<!--init some resources--> <xcl:parse-filter name="myFilter" source="file:///path/to/myFilter.xcl"/> <!--.../...--> <xcl:parse name="input" output-type="event" source="file:///path/to/file.xml"/> <xcl:filter filter="{ $myFilter }" name="step" source="{ $input }"/> <xcl:transform output="file:///path/to/result.xml" source="{ $step }"/>
The same compiled filter can be referred several times safely even in a multi-threaded environment.
The rule-based filters seen previously are all dealing with XML sources. For convenience, other kind of filters (not necessary rule-based) can be considered. For example, an implementation can define built-in filters for reading raw text inputs or binary inputs.
When referring to such filters, additional parameters may also be used.
XCL defines the following built-in filters but a given implementation can supply additional filters. The former is an XInclude filter that reads an XML source, the 2 latters are filters that read raw texts.
This predefined filter performs an XInclude inclusion as specified in the XInclude recommendation.
<xcl:parse-filter filter="http://ns.inria.org/active-tags/xcl/filters#XInclude" name="xinclude"/> <xcl:parse name="xml" source="file:///path/to/file.xml"/> <xcl:filter filter="{ $xinclude }" name="included" source="{ $xml }"/> <xcl:transform output="file:///path/to/result.xml" source="{ $included }"/>
The URI http://ns.inria.org/active-tags/xcl/filters#LineReader is reserved for a filter that can read a plain text stream and stands for an XML producer. When this filter is connected to a consumer (directly or indirectly), it fires events for the begin of the document, for each line read in the input, and for the end of the document.
<xcl:parse-filter filter="http://ns.inria.org/active-tags/xcl/filters#LineReader"
name="lineReader"/> <xcl:filter filter="{ $lineReader }" name="text" source="file:///path/to/file.txt"/> <xcl:filter name="step" source="{ $text }"> <xcl:rule pattern="/"> <xcl:forward> <poem><xcl:apply-rules/></poem> </xcl:forward> </xcl:rule> <xcl:rule pattern="text()"> <xcl:forward> <line><xcl:apply-rules/></line> </xcl:forward> </xcl:rule> </xcl:filter> <xcl:transform output="file:///path/to/result.xml" source="{ $step }"/>
If the content of the file file:///path/to/file.txt is :
From fairest creatures we desire increase, That thereby beauty's rose might never die, But as the riper should by time decease, His tender heir might bear his memory: But thou contracted to thine own bright eyes, Feed'st thy light's flame with self-substantial fuel, Making a famine where abundance lies, Thy self thy foe, to thy sweet self too cruel: Thou that art now the world's fresh ornament, And only herald to the gaudy spring, Within thine own bud buriest thy content, And tender churl mak'st waste in niggarding: Pity the world, or else this glutton be, To eat the world's due, by the grave and thee.
Then the output XML file will be (a smart indent has been added, it is not in the real output) :
<?xml version="1.0" encoding="iso-8859-1"?>
<poem> <line>From fairest creatures we desire increase,</line> <line>That thereby beauty's rose might never die,</line> <line>But as the riper should by time decease,</line> <line>His tender heir might bear his memory:</line> <line>But thou contracted to thine own bright eyes,</line> <line>Feed'st thy light's flame with self-substantial fuel,</line> <line>Making a famine where abundance lies,</line> <line>Thy self thy foe, to thy sweet self too cruel:</line> <line>Thou that art now the world's fresh ornament,</line> <line>And only herald to the gaudy spring,</line> <line>Within thine own bud buriest thy content,</line> <line>And tender churl mak'st waste in niggarding:</line> <line>Pity the world, or else this glutton be,</line> <line>To eat the world's due, by the grave and thee.</line> </poem>
The URI http://ns.inria.org/active-tags/xcl/filters#Tokenizer is reserved for a filter that can tokenize a plain text stream regarding a regular expression, and stands for an XML producer. When this filter is connected to a consumer (directly or indirectly), it fires events for the begin of the document, for each string around the tokens matched by the regular expression (tokens are stripped), and for the end of the document.
It accept the following parameters :
| Name | Value | Default |
|---|---|---|
| pattern | The pattern used for the tokenization | \s* |
| flags | The options for the interpretation of the regular expression | |
| buffer | The size of the buffer (char size) | 2048 |
The buffer size is used to store chunks of stream on which the regular expression is applied ; if nothing matches, the content of the buffer is used to fire a single character event. If the buffer is not big enough for the regular expression to be applied entirely, unexpected results might occur.
<xcl:parse-filter filter="http://ns.inria.org/active-tags/xcl/filters#Tokenizer" name="tokenizer"> <xcl:param name="pattern" value=",\s*"/> <xcl:param name="buffer" value="1024"/> </xcl:parse-filter>
When an action fails to run, it may invoke a fallback procedure with a failure cause and error datas.
The <xcl:fallback> element may be used as a local definition of a fallback process that will be invoked if its host action fails to run. Several elements may be defined for a single host action ; each must have an @id attribute different that identifies a fallback process, except one that is the default fallback action. When the host action fails to run, the fallback action that has the same identifier than the failure cause will be invoked ; if no fallback action matches the failure cause, the lookup of the fallback action is performed on the ancestors of the action that fails ; if still not found, the lookup sequence is tried again to find a default fallback action.
| Recovering a fatal error while XML parsing | |
|---|---|
In this example, after running the <xcl:parse> element, the $result property will contain a parsed XML document that contains :
<xcl:parse name="result" source="file:///path/to/file.xml">
<xcl:fallback id="xml:fatal-error">
<xcl:document name="result">
<error column="{ $xml:x-error/@column-number }" level="{ name( $xml:x-error ) }"The fallback process will be invoked only on fatal error as specified in the XML recommendation ; if it occurs, it will be invoked with the $xml:x-error property which contains the detailed informations about the error. | |
There is 2 ways to reuse a fallback definition :
Both of these techniques may be mixed.