|
For higher-level resources, like
<ACoffeeEditor>, you
will often want to create a merged HTML representation that contains state from the component resources.
This is easily done using XSLT's document() function.
ACoffeeEditor.xsl creates a representation of a particular coffee, including the coffee's
name, current price, and a form for setting the price. The XML only contains a pointer to the
<Coffee> resource and the
<SetAPrice> resource.
The following XML is returned by the Colombian
<ACoffeeEditor>
resource.
<list>
<doc schema="http://waterken.com/coffeebreak/ACoffeeEditor">
<viewer schema="http://waterken.com/doc/pointer/Link">
<target>hd6ypn3pse2cse27vuytwjyy2q</target>
</viewer>
<updater schema="http://waterken.com/doc/pointer/Link">
<target>sfyisoakazbplsh7xnxek6ogaa</target>
</updater>
</doc>
</list>
The viewer element points to the
<Coffee> resource. The
updater element points to the
<SetAPrice> resource.
To get the name and price, ACoffeeEditor.xsl must use a document() call.
document() enables the XSLT to get an additional resource representation. The stylesheet
uses a document() call to fetch the
<Coffee>
resource linked to by the viewer element:
<xsl:apply-templates select="document(viewer/target)" mode="viewer" />
As described in Applying a custom stylesheet, all template matches should
be done by type. XML fetched with a document() call is no exception. Using a mode
prevents confusion between ambiguous templates.
ACoffeeEditor.xsl creates an HTML FORM for setting the price of a coffee. The
XSLT for creating the price form is:
<form method="POST" action="?path=updater/">
<p>
Price:·
<xsl:choose>
<xsl:when test="string-length(substring-after(price, '.')) = 1">
<input type="text" name="doc.0" size="5">
<xsl:attribute name="value">
<xsl:value-of select="concat(price, '0')" />
</xsl:attribute>
</input>
<xsl:text> / unit</xsl:text>
</xsl:when>
...
<form>
The form action attribute contains the URL to which the form
should be posted. The set price invocation must be delivered not to the
<ACoffeeEditor>
resource, but to the component
<SetAPrice> resource.
This invocation routing is done using the path request parameter. The path
parameter specifies the path from the base resource to the target resource, in this case:
'updater/'.
A textfield accepts the new price. The name attribute of the textfield identifies this
input as the first argument in the invocation.
input type="text" name="doc.0" size="5" />
Each argument is identified by the doc.N string,
where N is the position of the argument in the declared
parameter list.
For composite parameters, such as a
<http://waterken.com/time/Time>, the
parameter identifier prefixes the path to the component datatype. For example, if the first argument
were a <Time>:
<input type="text" name="doc.0-hour" size="5" />
<input type="text" name="doc.0-minute" size="5" />
<input type="text" name="doc.0-second" size="5" />
As is specified in the HTTP RFC, the WaterkenTM server uses the HTTP
Accept request header to determine the content-type for the response. Mozilla specifies
that it prefers text/xml over text/html. To override this preference, you
should force the content-type to text/html by appending .html to the request
URI.
You now know enough to start webizing your database! The next section
concludes this tutorial.
|