CONTENTS |
This chapter is all about creating connections between documents and parts of documents the XLink and XPointer specifications. In HTML, you have hyperlinks, but XML has gone far beyond that, using the XLink, XPointer, XPath, and XBase specifications.
Unfortunately, this is another area of XML where the W3C is far ahead of the rest of the world. There are no concrete implementations of any of these specifications yet. Microsoft, which has been burned many times by implementing XML standards that have then changed, is just beginning to add support for XLinks and XPointers to Internet Explorer. Certainly, we'll see all these specifications implemented in future software, but for now, most of the material in this chapter is waiting for actual implementations.
XLinks specify how one document links to another document. XPointers specify locations inside a document, building on the XPath recommendation that we covered in Chapter 13, "XSL Transformations." I'll take a look at an overview now.
As of this writing, the XLink specification is a W3C working draft, released on February 21, 2000. You can find the most current version of this specification at http://www.w3.org/TR/xlink. You use XLinks to link one document to another. Here's what W3C says in the W3C working draft:
This specification defines the XML Linking Language (XLink), which allows elements to be inserted into XML documents in order to create and describe links between resources. It uses XML syntax to create structures that can describe the simple unidirectional hyperlinks of today's HTML, as well as more sophisticated links.
Here's an example to give you an idea what an XLink looks like. Unlike HTML hyperlinks, any element can be a link in XML. You specify that an element is a link with the attribute xlink:type like this, where I'm creating a simple XLink:
<MOVIE_REVIEW xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "simple" xlink:show = "new" xlink:href = "http://www.starpowdermovies.com/reviews.xml"> Mr. Blandings Builds His Dream House </MOVIE_REVIEW>
In this case, I'm creating a simple XLink, which is much like an HTML hyperlink, by setting the xlink:type attribute to "simple". I'm also setting the xlink:show attribute to "new", which means that XLink-aware software should open the linked-to document in a new window or other display context. I'm also setting the xlink:href attribute to the URI of the new document (which can be quite general and need not be in the URL form I've used here).
For the sake of familiarity, I'm starting with a simple XLink because it's much like an HTML link (although XLinks can become quite involved, as we'll see in this chapter). Besides basic unidirectional links, such as the simple link I've created here, you can also create bidirectional links as well as links between many documents and even document sets. In addition, you can do much more, including storing your links in link databases called linkbases.
XLinks let you link to a particular document, but you often need to be more precise than that. XPointers let you point to specific locations inside a document without having to modify that document by embedding special tags or markers.
To point to a specific location in a document, the XPointer specification builds on the XPath specification. As you recall, we covered the XPath specification in Chapter 13; it let you identify specific nodes in a document with expressions like this:
/child::*[position()=126]/child::*[position()=first()]
XPointers are now in the W3C candidate recommendation stage. As of this writing, the current document is as of June 7, 2000; you can find the most current version of this specification at http://www.w3.org/TR/xptr. Here's what W3C says about XPointers:
This specification defines the XML Pointer Language (XPointer), the language to be used as a fragment identifier for any URI-reference that locates a resource of Internet media type text/xml or application/xml. XPointer, which is based on the XML Path Language (XPath), supports addressing into the internal structures of XML documents. It allows for traversals of a document tree and choice of its internal parts based on various properties, such as element types, attribute values, character content, and relative position.
Although XPointers are built on the XPath specification (which you'll find covered in Chapter 13 and at http://www.w3.org/TR/xpath), the XPointer specification extends XPaths in ways that we'll see in this chapter.
How do you add an XPointer to a document's URI to identify a specific location in a document? You just append # (following the HTML usage for URLs that specify link targets) and then xpointer(), placing the XPath expression you want to use in the parentheses. Here's an example:
<MOVIE_REVIEW xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "simple" xlink:show = "new" xlink:href = "http://www.starpowdermovies.com/reviews.xml# xpointer(/child::*[position()=126]/child::*[position()=first()])"> Mr. Blandings Builds His Dream House </MOVIE_REVIEW>
That gives us an overview of XLinks and XPointers. I'm going to cover both these specifications in this chapter, as well as the XBase specification, starting now with XLinks.
XML VolatilityAs in most areas of XML not bound by W3C recommendations, it's important to realize that the XLink, XPointer, and XBase specifications are subject to change. They've been around for a while and are close to becoming candidate recommendations, so things shouldn't change much from what you see in this chapter. However, bear in mind that things can change when software implementations of these specifications appear, those implementations may also vary from the specifications in significant ways. It's the same old story once again watch out forstandards that change under your feet. |
Hyperlinks have long been an important part of HTML, and you create them with the HTML <A> element, like this:
<A HREF = "http://www.starpowdermovies.com/reviews.html#blandings"> Mr. Blandings Builds His Dream House <A>
The hyperlink appears in an HTML document either as text typically underlined and colored or as a clickable image. When clicked, the hyperlink can perform a variety of actions: navigating to a new document, as well as a specific location in that document; opening the new document in an existing frame or even a new window if you use the TARGET attribute; or executing JavaScript if you use the javascript: URL. Table 15.1 lists the official HTML attributes for the <A> element:
Attribute | Description |
---|---|
ACCESSKEY | Assigns a keyboard shortcut to the hyperlink. |
CHARSET | Specifies the character encoding of the target of the hyperlink. You set this to a RFC 2045 language character set string (the default value is ISO-8859-1). |
CLASS | Gives the style class of the element. |
COORDS | Sets the coordinate values (in pixels) appropriate to the accompanying SHAPE attribute to define a region of an image for image maps. |
DIR | Gives the direction of directionally neutral text. Set it to LTR for left-to-right text, or RTL for right-to-left text. |
HREF | Holds the target URL of the hyperlink. Either this attribute or the NAME attribute must be used. |
HREFLANG | Specifies the base language of the target indicated in the HREF attribute. Set this to RFC 1766 values. |
ID | Gives a unique identifier for the tag. |
LANG | Serves as the base language used for the tag. |
NAME | Set this to an anchor name, the name you want to use to refer to the enclosed items (such as text, images, and so on). Either this attribute or the HREF attribute must be used. |
REL | Specifies the relationship described by the hyperlink. |
REV | Essentially is the same as the REL attribute, but the syntax works in the reverse direction. |
SHAPE | Defines the type of region to be defined for mapping in an HTML AREA tag. |
STYLE | Is the inline style indicating how to render the element. |
TABINDEX | Sets the tab sequence of hyperlinks in the page. |
TARGET | Indicates the named frame for the HREF hyperlink to jump to. Set this to the name of a frame. |
TITLE | Holds title information for the element. |
TYPE | Specifies the MIME type of the target given in the HREF attribute. |
There's a lot of functionality here, but it all relies on the <A> element and the simplest type of hyperlink one that waits to be clicked and then navigates to a new document or document location.
Relationships between documents can be far more complex than that. For example, you might want to do one or more of the following:
Set up a link to point to 10 mirror sites of a main site, and let the browser select the one that's closest.
Link to an entire set of documents, complete with subsets, that the browser should search for the resource you want.
Set up a series of paths that lets the user navigate between a set of documents in various directions, but not in others.
And so on. XLinks let you perform all these kinds of linking.
XLinks are not restricted to any one element like the <A> element, which is to say that XLinks may not always appear in your documents in the traditional blue, underlined text (although, of course, they could, if you wanted them that way). Being able to make any element into an XLink is great because you can create elements that are always links to other resources. Users might even come to expect that, for example, if they come across anything formatted with, the <CITATION> element, that element will be linked to the cited material.
You create an XLink with attributes, not with specific elements. Specifically, you use the xlink:type attribute to create an XLink, setting it to one of the allowable types of XLinks: "simple", "extended", "locator", "arc", "resource", "title", or "none".
Table 15.2 lists the current XLink attributes.
Attribute | Description |
---|---|
xlink:actuate | This attribute determines when traversal operations occur. You can set this attribute to the official values of "onLoad", "onRequest", or "undefined", or other values as required by the software you're using. |
xlink:from | This attribute defines starting resources. |
xlink:href | This is the locator attribute, which supplies the data that allows an XLink application to find a remote resource. |
xlink:role | You use the role attribute to describe the function of a link's remote resource in a machine-readable fashion and, in the case of extended-type elements, to serve as a resource category label for traversal rules in arc-type elements. For example, search engines will be capable of reading this attribute. |
xlink:show | You use this attribute to indicate how you want to display the linked-to resource. XLink applications must recognize the following values: "new" (open a new display space), "replace" (replace the currently displayed data), "embed" (embed the new resource in the current one), and "undefined" (leaving the show function up to the displaying software). |
xlink:title | You use the title attribute to describe the function of a link's remote resource for people to understand. |
xlink:to | This attribute defines target or ending resources. |
xlink:type | This attribute sets the type of the XLink; it can be one of "simple", "extended", "locator", "arc", "resource", "title", or "none. We'll see what these types mean in this chapter. |
Using the XLink attributes, you can make an XLink mockup in browsers such as Internet Explorer. As an example, I'll create a mockup of a simple XLink here. Internet Explorer supports the onClick attribute, if you use it with an XML element. I'll add some JavaScript to that attribute to make the browser navigate to a new URI, using Internet Explorer's location object:
<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/css" href="xlink_example.css"?> <!DOCTYPE html SYSTEM "xlink_example.dtd"> <DOCUMENT> <P> Want to check out <LINK xml:type = "simple" href = "http://www.w3c.org" onClick="location.href='http://www.w3c.org'">W3C</LINK>? </P> </DOCUMENT>
I'm even supplying a style sheet, xlink_example.css, to make this XLink appear in the standard blue, underlined font; in fact, you can even make Internet Explorer's cursor change to a hand as it does for HTML hyperlinks with the cursor CSS property:
LINK {color: #0000FF; text-decoration: underline; cursor: hand}
The result appears in Figure 15.1, where the simple XLink functions much like an HTML hyperlink (which, of course, limits the whole concept of XLinks badly). You can click this link to make Internet Explorer navigate to a new document.
So when do you use which XLink attributes? It all depends on the type of link you're creating, as given by the xlink:type attribute. Depending on link type, some of these attributes are required, and some are optional. You can find the complete rules in Table 15.3, where the rows correspond to the various Xlink attributes, and the columns correspond to the various XLink types.
simple | extended | locator | arc | resource | title | |
---|---|---|---|---|---|---|
type | Required | Required | Required | Required | Required | Required |
href | Optional | Omitted | Required | Omitted | Omitted | Omitted |
role | Optional | Optional | Optional | Optional | Optional | Omitted |
title | Optional | Optional | Optional | Optional | Optional | Omitted |
show | Optional | Omitted | Omitted | Optional | Omitted | Omitted |
actuate | Optional | Omitted | Omitted | Optional | Omitted | Omitted |
from | Omitted | Omitted | Omitted | Optional | Omitted | Omitted |
to | Omitted | Omitted | Omitted | Optional | Omitted | Omitted |
Note that each of these attributes uses the xlink namespace; this namespace always has the value "http://www.w3.org/1999/xlink", as we saw in the earlier simple link example:
<MOVIE_REVIEW xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "simple" xlink:show = "new" xlink:href = "http://www.starpowdermovies.com/reviews.xml# xpointer(/child::*[position()=126]/child::*[position()=first()])"> Mr. Blandings Builds His Dream House </MOVIE_REVIEW>
Another W3C specification bears discussion while talking about linking and the relationship between documents: the XBase specification.
As of this writing, the XBase specification is in working draft stage, released on June 7, 2000. You can find the current version of this document at http://www.w3.org/TR/xmlbase. This specification lets you provide a base URI for XML documents, just like the HTML <BASE> element. In fact, the HTML <BASE> element is exactly the reason XBase exists W3C is committed to giving XLink all the power that HTML 4.0 linking has and then building on that. One of the aspects of linking in HTML 4.0 is the <BASE> element.
Here's how it works. You can use the xml:base element in an XML document to set the document's base URI. The other URIs in the document are then resolved using that value as a base. Note that xml:base uses the xml namespace, not the xlink namespace; the xml namespace is predefined in XML (that is, you don't have to define it to be able to use it in most XML parsers) as "http://www.w3.org/XML/1998/namespace". Here's an example:
<MOVIE_REVIEW xmlns:xlink = "http://www.w3.org/1999/xlink" xml:base="http://www.starpowder.com" xlink:type = "simple" xlink:show = "new" xlink:href = "reviews.xml"> Mr. Blandings Builds His Dream House </MOVIE_REVIEW>
Using the value assigned to the xml:base attribute, the URI in this example's xlink:href attribute, "reviews.xml", is resolved to the full URI "http://www.starpowder.com/reviews.xml". In this way, you can use xml:base to provide a base URI for a document (or even a specific element).
Note that if you're creating valid XML documents, you must declare XLink attributes, just like any other attributes. For example, you might use a declaration in a DTD like this for the previous example:
<?xml version = "1.0" standalone="yes"?> <!DOCTYPE MOVIE_REVIEW [ <!ELEMENT MOVIE_REVIEW (#PCDATA)> <!ATTLIST MOVIE_REVIEW xmlns:xlink CDATA #IMPLIED xml:base CDATA #IMPLIED xlink:type CDATA #REQUIRED xlink:href CDATA #IMPLIED xlink:show CDATA #IMPLIED xlink:actuate CDATA #IMPLIED xlink:title CDATA #IMPLIED> ]> <MOVIE_REVIEW xmlns:xlink = "http://www.w3.org/1999/xlink" xml:base="http://www.starpowder.com" xlink:type = "simple" xlink:show = "new" xlink:href = "reviews.xml"> Mr. Blandings Builds His Dream House </MOVIE_REVIEW>
You can also hard-code the values for most of the values in the XLink attributes, if you prefer, in which case, you have to supply a value for only the xlink:href attribute:
<?xml version = "1.0" standalone="yes"?> <!DOCTYPE MOVIE_REVIEW [ <!ELEMENT MOVIE_REVIEW (#PCDATA)> <!ATTLIST MOVIE_REVIEW xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink" xml:base CDATA #FIXED "http://www.starpowder.com" xlink:type CDATA #FIXED "simple" xlink:href CDATA #REQUIRED xlink:show CDATA #FIXED "new" xlink:actuate CDATA #FIXED "onRequest" xlink:title CDATA #IMPLIED> ]> <MOVIE_REVIEW xlink:href = "reviews.xml"> Mr. Blandings Builds His Dream House </MOVIE_REVIEW>
Because XLink is so general, declaring your XLink elements can get fairly involved XLink elements may even have child XLink elements, which have their own XLink children, and so on. But keep in mind that if you want to create a valid document, you have to declare them all in a DTD or schema.
We've seen the attributes you can use with XLinks in overview now. Because these attributes define XLinks, I'll take a look at each of them more detail now, starting with the most important one of all, the xlink:type attribute.
The xlink:type attribute defines the type of XLink you're creating. You can set this attribute to these values:
Value | Description |
---|---|
simple | Creates a simple link. |
extended | Creates an extended link. |
locator | Creates a locator link that points to a resource. |
arc | Creates an arc with multiple resources and various traversal paths. |
resource | Creates a resource link, which indicates a specific resource. |
title | Creates a title link. Such elements are useful, for example, for cases in which human-readable label information needs further element markup, or in which multiple titles are necessary for internationalization purposes. |
We've already seen how to create simple links:
<MOVIE_REVIEW xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "simple" xlink:show = "new" xlink:href = "http://www.starpowdermovies.com/reviews.xml# xpointer(/child::*[position()=126]/child::*[position()=first()])"> Mr. Blandings Builds His Dream House </MOVIE_REVIEW>
I'll take a look at the various other kinds of links in this chapter.
The xlink:href attribute is also called the locator attribute. This is the attribute that supplies the data that allows an XLink application to find a remote resource.
URI DefinitionAlthough XLinks can be quite general, they commonly use URIs to locate resources, and you usually use a URI in xlink:href. Now that we're examining the way linking works in XML, you might want to look up the formal definition of URIs, which you can find in its entirety at http://www.ics.uci.edu/pub/ietf/uri/rfc2396.txt. |
We've seen that you can set the xlink:href attribute to specify a document and an XPointer:
<MOVIE_REVIEW xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "simple" xlink:show = "new" xlink:href = "http://www.starpowdermovies.com/reviews.xml# xpointer(/child::*[position()=126]/child::*[position()=first()])"> Mr. Blandings Builds His Dream House </MOVIE_REVIEW>
We'll see how the values you assign to this attribute can become fairly involved when we work with XPointers.
Two important XLink attributes are xlink:role and xlink:title, which let you describe a remote resource. Both these attributes are optional. Here's an example putting both attributes to work:
<MOVIE_REVIEW xmlns:xlink = http://www.w3.org/1999/xlink xlink:type = "simple" xlink:show = "new" xlink:role = "MOVIE_REVIEW[EN]" xlink:title = "Review of 'Mr. Blandings Builds His Dream House'" xlink:href = "http://www.starpowdermovies.com/reviews.xml# xpointer(/child::*[position()=126]/child::*[position()=first()])"> Mr. Blandings Builds His Dream House </MOVIE_REVIEW>
The xlink:title attribute here has the value "Review of 'Mr. Blandings Builds His Dream House'". This is a human-readable description of the resource to which the link links; the idea here is that a person can read this text to get more information about the remote resource the link points to. An application might display this text on demand.
The text of the xlink:role attribute, on the other hand, is designed to be read by software. A link's role indicates the category of a link. In this case, the text of the link's role is "MOVIE_REVIEW[EN]".
There has been no attempt to standardize roles as there has been in the Remote Description Framework language that we first saw in Chapter 1, "Essential XML," because there are simply too many possibilities. Although search engines can use the link's role to classify the link, you usually use roles to define directional links when creating extended links, and I'll take a look at that soon.
If you want to create valid documents, you must declare the xlink:role and xlink:title attributes, as in this case, where I'm using a DTD and giving xlink:role the fixed value "MOVIE_REVIEW[EN]" in <MOVIE_REVIEW> elements:
<!ELEMENT MOVIE_REVIEW (#PCDATA)> <!ATTLIST MOVIE_REVIEW xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink" xlink:type CDATA #FIXED "simple" xlink:href CDATA #REQUIRED xlink:title CDATA #IMPLIED xlink:role CDATA #FIXED "MOVIE_REVIEW[EN]" >
You use the XLink xlink:show attribute to indicate how you want the linked-to resource displayed when the link is activated. The xlink:show attribute has four values that are predefined:
Value | Description |
---|---|
replace | Replaces the current resource in the same window, if there is one |
new | Opens a new display area, such as a new window, to display the new resource |
embed | Embeds the linked-to resource in the current resource |
undefined | Indicates that you are requesting no specific xlink:show setting |
Even though xlink:show has these predefined values, you can set your own values as well.
The default behavior of HTML links is to navigate to a linked-to document, replacing the current document with the new one. You can mimic that operation by assigning xlink:show a value of "replace":
<MOVIE_REVIEW xmlns:xlink = http://www.w3.org/1999/xlink xlink:type = "simple" xlink:show = "replace" xlink:href = "http://www.starpowdermovies.com/reviews.xml"> Mr. Blandings Builds His Dream House </MOVIE_REVIEW>
What this actually means in practice is application-specific. Although you'd expect the current document to be replaced with a new one, there are plenty of other possibilities. For example, a spreadsheet application may replace the displayed data, but not the overall display, with data from the linked-to resource. Or, the xlink:show attribute can make the application use a different style sheet when the link is activated. Again, the actual implementation is up to the software designer.
If the value of xlink:show is "new", activating the link typically opens a new window that displays the linked-to resource:
<MOVIE_REVIEW xmlns:xlink = http://www.w3.org/1999/xlink xlink:type = "simple" xlink:show = "new" xlink:href = "http://www.starpowdermovies.com/reviews.xml"> Mr. Blandings Builds His Dream House </MOVIE_REVIEW>
However, as before, there are plenty of possibilities; a value of "new" might simply mean that a new column is added to a table or that a new line is displayed in a graph. It's a good idea to be considerate here bear in mind that users coming from HTML will not be used to having links that automatically open new windows, if that's what your link is going to do. You might make sure you add some explanatory text otherwise, such behavior might be annoying.
Similarly, the attribute value "embed" is subject to interpretation. The idea here is that when a link is activated, the linked-to resource is embedded in the current display or document, although what is actually embedded and how is up to the application. For example, say that we linked to planets.xml, which we saw in the previous few chapters:
<?xml version="1.0"?> <?xml-stylesheet type="text/xml" href="planets.xsl"?> <PLANETS> <PLANET> <NAME>Mercury</NAME> <MASS UNITS="(Earth = 1)">.0553</MASS> <DAY UNITS="days">58.65</DAY> <RADIUS UNITS="miles">1516</RADIUS> <DENSITY UNITS="(Earth = 1)">.983</DENSITY> <DISTANCE UNITS="million miles">43.4</DISTANCE><!--At perihelion--> </PLANET> <PLANET> <NAME>Venus</NAME> <MASS UNITS="(Earth = 1)">.815</MASS> <DAY UNITS="days">116.75</DAY> <RADIUS UNITS="miles">3716</RADIUS> <DENSITY UNITS="(Earth = 1)">.943</DENSITY> <DISTANCE UNITS="million miles">66.8</DISTANCE><!--At perihelion--> </PLANET> <PLANET> <NAME>Earth</NAME> <MASS UNITS="(Earth = 1)">1</MASS> <DAY UNITS="days">1</DAY> <RADIUS UNITS="miles">2107</RADIUS> <DENSITY UNITS="(Earth = 1)">1</DENSITY> <DISTANCE UNITS="million miles">128.4</DISTANCE><!--At perihelion--> </PLANET> </PLANETS>
Here's how the links to the various planets might look. I'm anticipating the use of XPointers here to pick out the specific planets in planets.xml; note that the xlink:show values are all "embed" here:
<?xml version = "1.0"> <ASTRO_NEWS> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "simple" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 1]"> Mercury </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "simple" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 2]"> Venus </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "simple" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 3]"> Earth </PLANET_DATA> <ASTRO_NEWS>
After all these links are activated, the data from the various <PLANET> elements might be inserted into the current display, something like this (again, the details are up to the host application):
<?xml version = "1.0"> <ASTRO_NEWS> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" <NAME>Mercury</NAME> <MASS UNITS="(Earth = 1)">.0553</MASS> <DAY UNITS="days">58.65</DAY> <RADIUS UNITS="miles">1516</RADIUS> <DENSITY UNITS="(Earth = 1)">.983</DENSITY> <DISTANCE UNITS="million miles">43.4</DISTANCE><!--At perihelion--> </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" <NAME>Venus</NAME> <MASS UNITS="(Earth = 1)">.815</MASS> <DAY UNITS="days">116.75</DAY> <RADIUS UNITS="miles">3716</RADIUS> <DENSITY UNITS="(Earth = 1)">.943</DENSITY> <DISTANCE UNITS="million miles">66.8</DISTANCE><!--At perihelion--> </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" <NAME>Earth</NAME> <MASS UNITS="(Earth = 1)">1</MASS> <DAY UNITS="days">1</DAY> <RADIUS UNITS="miles">2107</RADIUS> <DENSITY UNITS="(Earth = 1)">1</DENSITY> <DISTANCE UNITS="million miles">128.4</DISTANCE><!--At perihelion--> </PLANET_DATA> <ASTRO_NEWS>
You can also set xlink:show to a value of "undefined", in which case you're indicating to the application that you don't have a display preference, which usually means that it's up to the application. In fact, it's up to the application what happens in any case, because the application may ignore any of the values you carefully assign to xlink:show, especially if it's not capable of handling what you want (as when you set xlink:show to "new" but the browser can't handle multiple windows).
You're also free to set xlink:show to your own values. For example, setting it to "new_row" might add a new row to a table for displaying data. You might also use this attribute to indicate something about the format in which documents are displayed, rather than how they are displayed, as when you set xlink:show to the name of a style sheet. Or, you might set JavaScript code to execute in this attribute's value when the link is activated.
Don't forget that you need to declare xlink:show if you want to create valid documents. That might look something like this in a DTD:
<!ELEMENT ASTRO_NEWS> <!ATTLIST ASTRO_NEWS xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink" xlink:type CDATA #FIXED "simple" xlink:href CDATA #REQUIRED xlink:show (new | replace | embed | undefined) #IMPLIED "replace">
You can use the xlink:actuate attribute to indicate when a link should be traversed. The xlink:actuate attribute has these predefined values:
Value | Description |
---|---|
onRequest | Indicates that the link should be traversed only on the user's request |
onLoad | Indicates that the link should be traversed when the document or resource is loaded |
undefined | Indicates that you have no preference for the xlink:actuate action |
You can also set your own values for xlink:actuate.
The first of the predefined values, "onRequest", indicates that the user should request the link to be traversed before any action takes place. Typically, the user request takes the form of a mouse click, as in our earlier mockup of a simple link in Internet Explorer, where we can use the "onRequest" value:
<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/css" href="xlink_example.css"?> <!DOCTYPE html SYSTEM "xlink_example.dtd"> <DOCUMENT> <P> Want to check out <LINK xml:type = "simple" href = "http://www.w3c.org" xlink:actuate = "onRequest" onClick= "location.href='http://www.w3c.org'">W3C</LINK>? </P> </DOCUMENT>
If you set the value of xlink:actuate to "onLoad", the link is traversed when the resource containing it is loaded. For example, you might have a link to an image map's image and want to load it as soon as the containing document is loaded. That might look something like this:
<IMAGE_MAP xmlns:xlink=http://www.w3.org/1999/xlink xlink:type="simple" xlink:href="http://www.starpowder.com/gifs/image_map.gif" xlink:actuate="onLoad"> </IMAGE_MAP>
You can also set xlink:actuate to "undefined", which means that when the link is traversed is up to the application. (Of course, it's up to the application in any case, even when you specify any other value for xlink:actuate.)
You can also set your own values for xlink:actuate. For example, you might define your own application-specific values, such as "onLoadData", "onShowImage", or "onUnload".
If you want to create valid XML documents, of course, you'll have to declare xlink:actuate, and that might look something like this in a DTD:
<!ELEMENT ASTRO_NEWS> <!ATTLIST ASTRO_NEWS xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink" xlink:type CDATA #FIXED "simple" xlink:href CDATA #REQUIRED xlink:show (new | replace | embed | undefined) #IMPLIED "replace" xlink:actuate (onRequest | onLoad | undefined) #IMPLIED "onRequest">
You may be accustomed to the idea of simple links much as they work in HTML, and as I've discussed them previously, but here's where we broaden things by getting into extended links. Extended links are very general and really indicate relationships between resources. An extended link can involve multiple resources, multiple paths between those resources, bidirectional paths, and "out-of-line" links. It helps to think very generally here, in terms of all the possible relationships you might have between data resources.
Extended Link TerminologyThe upcoming concepts may seem very vague when compared to the concrete functionality of simple links, but keep in mind that W3C is trying to let you describe, in XML terms, all the possible relationships that there might be among multiple resources and how those relationships work. It's a big job. In technical terms, an extended link is called a directed labeled graph. The resources that it connects are called the vertices, and the actual links between resources are the edges of the graph. |
In general terms, then, an extended link is made up of the connections between a set of resources. Such resources may be local, which means that they're actually part of the extended link element, or remote, which means that they're not part of the extended link element (but does not mean that they have to be in another document). If a link does not contain any local resources at all, it's called an out-of-line link.
So how does an application use an extended link? That's completely up to the application. I'll provide some ideas here, but so far, things are really up in the air. To my knowledge, no generally available software packages implement true extended links.
A hypothetical example might be an expert system (for example, artificial intelligence or intelligent agents), in which the links between multiple resources are traversed depending on yes or no answers to questions. The idea here is that by answering a series of questions, an expert system can progressively narrow a search and direct you to a resource that will provide the answer to quite complex queries.
As mentioned, resources that participate in an extended link can be either local or remote. A local resource is part of the extended link itself and is contained in an element that has its xlink:type attribute set to "resource".
On the other hand, remote resources are outside the extended link element, but not necessarily in another document. You use locator elements to point to remote resources; those elements have their xlink:type attributes set to "locator". When you create a locator element, you must also give its xlink:href attribute a value that points to the remote resource.
Here's an example of an extended link. This link contains four resources two inline links and two out-of-line links:
<ASTRO_DATA xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="extended" xlink:title="Planetary Data"> <NAME xlink:type="resource" xlink:role="NAME"> Planetary Data </NAME> <DATE xlink:type="resource" xlink:role="LAST_UPDATED"> September 1, 2001 </DATE> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 1]"> xlink:title="Mercury" xlink:role="PLANETARY_DATA" </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 2]"> xlink:title="Venus" xlink:role="PLANETARY_DATA" </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 3]"> xlink:title="Earth" xlink:role="PLANETARY_DATA" </PLANET_DATA> </ASTRO_DATA>
The inline links here are those links that have the xlink:type value "resource" and whose resources are actually contained in the linking element. In this case, that's the <NAME> and <DATE> links, both of which contain a local resource (which is simply text here, although it could consist of multiple nested XML elements, if you prefer).
The out-of-line links here have the xlink:type attribute value "locator". These links serve to locate remote resources, which may be in the same document or in another document. In this example, the remote resources are all in another document, planets.xml.
As before, if you want to create valid documents, you must declare the attributes and elements you're using. In this example, that might look like this, where I'm adding a DTD:
<?xml version = "1.0"?> <!DOCTYPE ASTRO_DATA [ <!ELEMENT ASTRO_DATA (NAME, DATE, PLANET_DATA*) > <!ATTLIST ASTRO_DATA xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink" xlink:type (extended) #FIXED "extended" xlink:title CDATA #IMPLIED xlink:role CDATA #IMPLIED> <!ELEMENT NAME (#PCDATA)> <!ATTLIST NAME xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink" xlink:type CDATA #FIXED "resource" xlink:role CDATA #IMPLIED xlink:title CDATA #IMPLIED > <!ELEMENT DATE (#PCDATA)> <!ATTLIST DATE xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink" xlink:type CDATA #FIXED "resource" xlink:role CDATA #IMPLIED xlink:title CDATA #IMPLIED > <!ELEMENT PLANET_DATA (#PCDATA)> <!ATTLIST PLANET_DATA xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink" xlink:type CDATA #FIXED "locator" xlink:href CDATA #REQUIRED xlink:role CDATA #IMPLIED xlink:title CDATA #IMPLIED xlink:show CDATA #IMPLIED > ]> <ASTRO_DATA xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="extended" xlink:title="Planetary Data"> <NAME xlink:type="resource" xlink:role="NAME"> Planetary Data </NAME> <DATE xlink:type="resource" xlink:role="LAST_UPDATED"> September 1, 2001 </DATE> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 1]"> xlink:title="Mercury" xlink:role="PLANETARY_DATA"> </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 2]"> xlink:title="Venus" xlink:role="PLANETARY_DATA"> </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 3]"> xlink:title="Earth" xlink:role="PLANETARY_DATA"> </PLANET_DATA> </ASTRO_DATA>
So far, all we've done is indicate what elements that participate in an extended link represent local or remote resources. You can do more if you use the xlink:from and xlink:to attributes, which enable you to create directed links, or arcs.
In simple links, there's little question where to go when the link is activated: The xlink:href attribute tells you all you need to know. However, extended links are more complex when you want to traverse the link we created in the last section, what should happen? There are all kinds of paths among the various resources.
Each of the possible paths between resources is called an arc. You represent arcs in XML elements by setting the xlink:type attribute to "arc".
To specify how an arc works, you can use attributes like xlink:show and xlink:actuate. Here's the important part: Arc elements also have xlink:from and xlink:to elements to specify traversal paths. The xlink:from attribute indicates what resource an arc comes from, and the xlink:to attribute indicates what resource it goes to. You set the values of xlink:from and xlink:to to match the xlink:role attribute of the source and target resources.
Here's an example. In this case, I'll modify the previous example by renaming the <NAME> element <START>, and I'll include three arcs: one from the <START> element to each of the three <PLANET_DATA> elements (individual arcs always go from one source resource to one target resource). I'll support the arcs with elements named <LOOKUP>. Here's what it looks like:
<?xml version = "1.0"?> <ASTRO_DATA xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="extended" xlink:title="Planetary Data"> <START xlink:type="resource" xlink:role="START"> Planetary Data </START> <DATE xlink:type="resource" xlink:role="LAST_UPDATED"> September 1, 2001 </DATE> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 1]"> xlink:title="Mercury" xlink:role="Mercury"> </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 2]"> xlink:title="Venus" xlink:role="Venus"> </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 3]"> xlink:title="Earth" xlink:role="Earth"> </PLANET_DATA> <LOOKUP xlink:type = "arc" xlink:from = "START" xlink:to = "Mercury" xlink:show="new" xlink:actuate="onRequest"> </LOOKUP> <LOOKUP xlink:type = "arc" xlink:from = "START" xlink:to = "Venus" xlink:show="new" xlink:actuate="onRequest"> </LOOKUP> <LOOKUP xlink:type = "arc" xlink:from = "START" xlink:to = "Earth" xlink:show="new" xlink:actuate="onRequest"> </LOOKUP> </ASTRO_DATA>
As usual, you must declare the elements and attributes you're using if you want a valid document; that might look something like this with a DTD:
<?xml version = "1.0"?> <!DOCTYPE ASTRO_DATA [ <!ELEMENT ASTRO_DATA (START, DATE, PLANET_DATA*, LOOKUP*) > <!ATTLIST ASTRO_DATA xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink" xlink:type (extended) #FIXED "extended" xlink:title CDATA #IMPLIED xlink:role CDATA #IMPLIED> <!ELEMENT START (#PCDATA)> <!ATTLIST START xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink" xlink:type CDATA #FIXED "resource" xlink:role CDATA #IMPLIED xlink:title CDATA #IMPLIED> <!ELEMENT DATE (#PCDATA)> <!ATTLIST DATE xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink" xlink:type CDATA #FIXED "resource" xlink:role CDATA #IMPLIED xlink:title CDATA #IMPLIED> <!ELEMENT PLANET_DATA (#PCDATA)> <!ATTLIST PLANET_DATA xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink" xlink:type CDATA #FIXED "locator" xlink:href CDATA #REQUIRED xlink:role CDATA #IMPLIED xlink:title CDATA #IMPLIED xlink:show CDATA #IMPLIED> <!ELEMENT LOOKUP (#PCDATA)> <!ATTLIST LOOKUP xlink:type CDATA #FIXED "arc" xlink:from CDATA #IMPLIED xlink:to CDATA #IMPLIED xlink:show CDATA #IMPLIED xlink:actuate (onRequest | onLoad | undefined) #IMPLIED> ]> <ASTRO_DATA xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="extended" xlink:title="Planetary Data"> <START xlink:type="resource" xlink:role="START"> Planetary Data </START> <DATE xlink:type="resource" xlink:role="LAST_UPDATED"> September 1, 2001 </DATE> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 1]"> xlink:title="Mercury" xlink:role="Mercury"> </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 2]"> xlink:title="Venus" xlink:role="Venus"> </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 3]"> xlink:title="Earth" xlink:role="Earth"> </PLANET_DATA> <LOOKUP xlink:type = "arc" xlink:from = "START" xlink:to = "Mercury" xlink:show="new" xlink:actuate="onRequest"> </LOOKUP> <LOOKUP xlink:type = "arc" xlink:from = "START" xlink:to = "Venus" xlink:show="new" xlink:actuate="onRequest"> </LOOKUP> <LOOKUP xlink:type = "arc" xlink:from = "START" xlink:to = "Earth" xlink:show="new" xlink:actuate="onRequest"> </LOOKUP> </ASTRO_DATA>
You don't need to have an arc refer to one specific resource, as I've done here. For example, here all three <PLANET_DATA> elements have the same role, PLANETARY_DATA, so this single <LOOKUP> element defines three arcs, one to each <PLANET_DATA> resource:
<?xml version = "1.0"?> <ASTRO_DATA xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="extended" xlink:title="Planetary Data"> <START xlink:type="resource" xlink:role="START"> Planetary Data </START> <DATE xlink:type="resource" xlink:role="LAST_UPDATED"> September 1, 2001 </DATE> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 1]"> xlink:title="Mercury" xlink:role="PLANETARY_DATA"> </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 2]"> xlink:title="Venus" xlink:role="PLANETARY_DATA"> </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 3]"> xlink:title="Earth" xlink:role="PLANETARY_DATA"> </PLANET_DATA> <LOOKUP xlink:type = "arc" xlink:from = "START" xlink:to = "PLANETARY_DATA" xlink:show="new" xlink:actuate="onRequest"> </LOOKUP> </ASTRO_DATA>
In fact, you can omit an xlink:from or xlink:to attribute altogether, in which case arcs are created between the particular element and all the locator elements in the extended link (which can include the element that omits the xlink:from or xlink:to attribute itself).
The way the xlink:from and xlink:to attributes are actually used is up to the application that's reading the containing document.
When a link does not contain any of the resources it's linking to, it's called an out-of-line link. Inline links are part of the resources they're part of, but out-of-line links are not part of the same resource. There's a big movement to try to separate markup from content as much as possible. (This is the motivation behind the big switch in HTML 4.0 to working with style sheets instead of dedicated elements such as <CENTER> and the external code modules called behaviors in Internet Explorer.) Using out-of-line links is very attractive, if that's the way you want to go.
You can place out-of-line links in their own documents, called linkbases. The actual set of out-of-line links in a linkbase is called a linkset.
Here's an example. In this case, all the links in this document are to resources that are not part of the document, so this is a linkbase:
<?xml version = "1.0"?> <ASTRO_DATA xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="extended" xlink:title="Planetary Data"> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml"> xlink:title="START" xlink:role="START"> </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 1]"> xlink:title="Mercury" xlink:role="Mercury"> </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 2]"> xlink:title="Venus" xlink:role="Venus"> </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 3]"> xlink:title="Earth" xlink:role="Earth"> </PLANET_DATA> <LOOKUP xlink:type = "arc" xlink:from = "START" xlink:to = "Mercury" xlink:show="new" xlink:actuate="onRequest"> </LOOKUP> <LOOKUP xlink:type = "arc" xlink:from = "START" xlink:to = "Venus" xlink:show="new" xlink:actuate="onRequest"> </LOOKUP> <LOOKUP xlink:type = "arc" xlink:from = "START" xlink:to = "Earth" xlink:show="new" xlink:actuate="onRequest"> </LOOKUP> </ASTRO_DATA>
In this case, all the resources linked to are outside the document. I've added locator links to all the planets in planets.xml, and arcs from the starting position in that document to the planets as well. You typically have three types of links in a linkbase: extended links, locator links, and arcs. You cannot have any links that are of type resource.
Linkbases are subject to the same rules as other XML documents, so you can provide them with DTD if you want to validate them, something like this:
<?xml version = "1.0"?> <!DOCTYPE ASTRO_DATA [ <!ELEMENT ASTRO_DATA (PLANET_DATA*, LOOKUP*) > <!ATTLIST ASTRO_DATA xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink" xlink:type (extended) #FIXED "extended" xlink:title CDATA #IMPLIED xlink:role CDATA #IMPLIED> <!ELEMENT PLANET_DATA (#PCDATA)> <!ATTLIST PLANET_DATA xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink" xlink:type CDATA #FIXED "locator" xlink:href CDATA #REQUIRED xlink:role CDATA #IMPLIED xlink:title CDATA #IMPLIED xlink:show CDATA #IMPLIED> <!ELEMENT LOOKUP (#PCDATA)> <!ATTLIST LOOKUP xlink:type CDATA #FIXED "arc" xlink:from CDATA #IMPLIED xlink:to CDATA #IMPLIED xlink:show CDATA #IMPLIED xlink:actuate (onRequest | onLoad | undefined) #IMPLIED> ]> <ASTRO_DATA xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="extended" xlink:title="Planetary Data"> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml"> xlink:title="START" xlink:role="START"> </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 1]"> xlink:title="Mercury" xlink:role="Mercury"> </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 2]"> xlink:title="Venus" xlink:role="Venus"> </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 3]"> xlink:title="Earth" xlink:role="Earth"> </PLANET_DATA> <LOOKUP xlink:type = "arc" xlink:from = "START" xlink:to = "Mercury" xlink:show="new" xlink:actuate="onRequest"> </LOOKUP> <LOOKUP xlink:type = "arc" xlink:from = "START" xlink:to = "Venus" xlink:show="new" xlink:actuate="onRequest"> </LOOKUP> <LOOKUP xlink:type = "arc" xlink:from = "START" xlink:to = "Earth" xlink:show="new" xlink:actuate="onRequest"> </LOOKUP> </ASTRO_DATA>
You can elaborate out-of-line linksets as much as you like; here, I'm adding arcs that will add a "next" and "previous" link to each planet:
<?xml version = "1.0"?> <ASTRO_DATA xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="extended" xlink:title="Planetary Data"> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml"> xlink:title="START" xlink:role="START"> </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 1]"> xlink:title="Mercury" xlink:role="Mercury"> </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 2]"> xlink:title="Venus" xlink:role="Venus"> </PLANET_DATA> <PLANET_DATA xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "locator" xlink:show = "embed" xlink:href = "http://www.starpowdermovies.com/planets.xml# xpointer(/descendant::PLANET[position() = 3]"> xlink:title="Earth" xlink:role="Earth"> </PLANET_DATA> <LOOKUP xlink:type = "arc" xlink:from = "START" xlink:to = "Mercury" xlink:show="new" xlink:actuate="onRequest"> </LOOKUP> <LOOKUP xlink:type = "arc" xlink:from = "START" xlink:to = "Venus" xlink:show="new" xlink:actuate="onRequest"> </LOOKUP> <LOOKUP xlink:type = "arc" xlink:from = "START" xlink:to = "Earth" xlink:show="new" xlink:actuate="onRequest"> </LOOKUP> <NEXT xlink:type = "arc" xlink:from = "Mercury" xlink:to = "Venus" xlink:show="new" xlink:actuate="onRequest"> </NEXT> <NEXT xlink:type = "arc" xlink:from = "Venus" xlink:to = "Earth" xlink:show="new" xlink:actuate="onRequest"> </NEXT> <NEXT xlink:type = "arc" xlink:from = "Earth" xlink:to = "Mercury" xlink:show="new" xlink:actuate="onRequest"> </NEXT> <PREVIOUS xlink:type = "arc" xlink:from = "Earth" xlink:to = "Venus" xlink:show="new" xlink:actuate="onRequest"> </PREVIOUS> <PREVIOUS xlink:type = "arc" xlink:from = "Venus" xlink:to = "Mercury" xlink:show="new" xlink:actuate="onRequest"> </PREVIOUS> <PREVIOUS xlink:type = "arc" xlink:from = "Mercury" xlink:to = "Earth" xlink:show="new" xlink:actuate="onRequest"> </PREVIOUS> </ASTRO_DATA>
The next question is this: Because out-of-line links are outside all resources they reference, how does application software that deals with those resources know how to find those links? The W3C specification is unclear on this point, much as it is on connecting external style sheets to XML documents. The idea here is that the application itself is responsible for finding such linkbases.
Admittedly, it is hard to specify how applications should find linkbases if you want to keep markup and content separate, which means that you can't embed a link to a linkbase in a resource (as when you're annotating someone else's work but don't have access to the source documents).
However, if you can add a link to a linkbase in a resource, W3C suggests a way to do so: You can use the predefined role xlink:external-linkbase to create links to a linkbase, something like this:
<EXTERNAL_LINKS xlink:type="simple" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:role="xlink:external-linkset" xlink:href="linkbase.xml"/> </EXTERNAL_LINKS>
So far in this chapter, I've said that you use the xlink:href attribute to locate resources, and I've left it at that. However, there is more to it than that: You can do more than just place a URI in this attribute you can also use XPointers to locate specific locations or sections of a document.
In the beginning of this chapter, I took a look at a link that used an XPointer to locate a specific element in a document; that example looked like this:
<MOVIE_REVIEW xmlns:xlink = "http://www.w3.org/1999/xlink" xlink:type = "simple" xlink:show = "new" xlink:href = "http://www.starpowdermovies.com/reviews.xml# xpointer(/child::*[position()=126]/child::*[position()=first()])"> Mr. Blandings Builds His Dream House </MOVIE_REVIEW>
You can see the XPointer part here:
xpointer(/child::*[position()=126]/child::*[position()=first()])
This XPointer is appended to the URI I'm using here, following a # character.
You might notice that this XPointer expression looks a lot like the XPath expressions we used in Chapter 13, and with good reason XPointers are built on XPaths, with certain additions that I'll note here.
Because XPointers are built on XPaths, they have all the power of XPaths. Among other things, this means that you can use an XPointer made up of location steps that target an individual location in a document without having to add any markup to that document. You can also use the id() function to target specific elements if you do want to add ID attributes to those elements.
However, because XPointers extend XPaths, there are some differences. The biggest difference is that because users can select parts of documents using the mouse, if they prefer, XPointers enable you to select points and ranges in addition to the normal XPath nodes. A point is just what it sounds like: a specific location in a document. A range is made up of all the XML between two points, which can include part of elements and text strings.
To support points and ranges, XPointer extends the idea of nodes into locations. Every location is an XPath node, a point, or a range. Therefore, node sets become location sets in the XPointer specification.
How do you create an XPointer? Like XPaths, XPointers are made of location paths that are divided into location steps, separated by the / character. A location step is made up of an axis, a node test, and zero or more predicates, like this:
axis::node_test[predicate]
For example, in the expression
child::PLANET[position() = 5]
child is the name of the axis, PLANET is the node test, and [position() = 5] is a predicate.
You can create location paths with one or more location steps, such as /descendant::PLANET/child::NAME, which selects all the <NAME> elements that have a <PLANET> parent.
XPointers augment what's available with XPaths, so I'm going to take a look at these three parts axes, node tests, and predicates for XPointers now.
The XPointer axes are the same as the XPath axes, and we're already familiar with them. Axes tell you which direction you should search and give you a starting position to search from. Here's the list of possible axes:
Axis | Description |
---|---|
ancestor | Holds the ancestors of the context node. The ancestors of the context node are the parent of the context node and the parent's parent and so forth, back to and including the root node. |
ancestor-or-self | Holds the context node and the ancestors of the context node. |
attribute | Holds the attributes of the context node. |
child | Holds the children of the context node. |
descendant | Holds the descendants of the context node. A descendant is a child, or a child of a child, and so on. |
descendant-or-self | Contains the context node and the descendants of the context node. |
following | Holds all nodes in the same document as the context node that come after the context node. |
following-sibling | Holds all the following siblings of the context node. A sibling is a node on the same level as the context node. |
namespace | Holds the namespace nodes of the context node. |
parent | Holds the parent of the context node. |
preceding | Contains all nodes that come before the context node. |
preceding-sibling | Contains all the preceding siblings of the context node. A sibling is a node on the same level as the context node. |
self | Contains the context node. |
Although XPointers use the same axes as XPaths, there are some new node tests. We'll take a look at these next.
Here are the node tests you can use with XPointers, and what they match:
Node Test | Matches |
* | Any element |
node() | Any node |
text() | A text node |
comment() | A comment node |
processing-instruction() | A processing instruction node |
point() | A point in a resource |
range() | A range in a resource |
Note in particular the last two point() and range(). These correspond to the two new constructs added in XPointers, points and ranges, and I'll talk more about them at the end of this chapter.
To extend XPath to include points and ranges, the XPointer specification created the concept of a location, which can be an XPath node, a point, or a range. However, node tests are still called node tests, not location tests; when discussing node tests, the XPointer specification specifically extends the definition of node types to include points and ranges so that node tests can work with those types. For the moment, then, we're stuck with the idea that locations can be XPath nodes, points, or ranges and that the node types in node tests can also be XPath nodes, points, or ranges. Presumably, this contradiction will be cleared up in the final XPointer recommendation.
XPointers support the same types of expressions as XPaths. As in Chapter 13, these are the possible types of expressions you can use in predicates (refer to Chapter 13 for more information):
Node sets
Booleans
Numbers
Strings
Result tree fragments
As we saw in Chapter 13, there are functions to deal with all these types in XPath. The XPointer specification supports all those functions and also adds functions to cast subexpressions to the particular types defined in XPath, such as boolean(), string(), text(), and number(). It also adds the function unique(), to enable you to test whether an XPointer locates a single location rather than multiple locations or no locations.
XPointer also makes some additions to the functions that return location sets, and I'll take a look at those functions now.
Four XPointer functions return location sets:
Function | Description |
---|---|
id() | Returns all the elements with a specific ID |
root() | Returns a location set with one location, the root node |
here() | Returns a location set with one location, the current location |
origin() | Same as here(), except that this function is used with out-of-line links |
The id() function is the one we saw in Chapter 13 when discussing XPath. You can use this function to return all locations with a given ID.
The root() function works just like the / character it refers to the root node (which is not the same as the document node the root node corresponds to the very beginning of the prolog, while the document node corresponds to the top-level element in the document). The root() function is not actually part of the XPath specification, but the XPointer specification refers to it as if it were. Whether or not it will be included in the final XPointer recommendation is unclear.
The here() function refers to the current element. This is useful because XPointers are usually stored in text nodes or attribute values, and you might want to refer to the current element (not just the current node). For example, you might want to refer to the second previous <NAME> sibling element of the element that contains an XPointer, and you can use an expression like this to do so:
here()/preceding-sibling::NAME[position() = 2]
The origin() function is much like the here() function, but you use it with out-of-line links. It refers to the original element, which may be in another document, from which the current link was activated. This can be very helpful if the link itself is in a linkbase and needs to refer not to the element that the link is in, but the original element from which the link is activated.
You can use the abbreviated XPath syntax in XPointers as well. I'll take a look at a few examples, using planets.xml as the document we'll be navigating:
<?xml version="1.0"?> <?xml-stylesheet type="text/xml" href="planets.xsl"?> <PLANETS> <PLANET> <NAME>Mercury</NAME> <MASS UNITS="(Earth = 1)">.0553</MASS> <DAY UNITS="days">58.65</DAY> <RADIUS UNITS="miles">1516</RADIUS> <DENSITY UNITS="(Earth = 1)">.983</DENSITY> <DISTANCE UNITS="million miles">43.4</DISTANCE><! At perihelion > </PLANET> <PLANET> <NAME>Venus</NAME> <MASS UNITS="(Earth = 1)">.815</MASS> <DAY UNITS="days">116.75</DAY> <RADIUS UNITS="miles">3716</RADIUS> <DENSITY UNITS="(Earth = 1)">.943</DENSITY> <DISTANCE UNITS="million miles">66.8</DISTANCE><! At perihelion > </PLANET> <PLANET> <NAME>Earth</NAME> <MASS UNITS="(Earth = 1)">1</MASS> <DAY UNITS="days">1</DAY> <RADIUS UNITS="miles">2107</RADIUS> <DENSITY UNITS="(Earth = 1)">1</DENSITY> <DISTANCE UNITS="million miles">128.4</DISTANCE><! At perihelion > </PLANET> </PLANETS>
Here are a few XPointer examples note that, as with XPath, you can use the [] operator; here, it extracts a particular location from a location set.
Example | Description |
---|---|
PLANET | Returns the <PLANET> element children of the context node. |
* | Returns all element children of the context node. |
text() | Returns all text node children of the context node. |
@UNITS | Returns the UNITS attribute of the context node. |
@* | Returns all the attributes of the context node. |
PLANET[3] | Returns the third <PLANET> child of the context node. |
PLANET[first()] | Returns the first <PLANET> child of the context node. |
*/PLANET | Returns all <PLANET> grandchildren of the context node. |
/PLANETS/PLANET[3] /NAME[2] | Returns the second <NAME> element of the third <PLANET>element of the <PLANETS> element. |
//PLANET | Returns all the <PLANET> descendants of the document root. |
PLANETS//PLANET | Returns the <PLANET> element descendants of the <PLANETS> element children of the context node. |
//PLANET/NAME | Returns all the <NAME> elements that have a <PLANET> parent. |
. | Returns the context node itself. |
.//PLANET | Returns the <PLANET> element descendants of the context node. |
.. | Returns the parent of the context node. |
../@UNITS | Returns the UNITS attribute of the parent of the context node. |
PLANET[NAME] | Returns the <PLANET> children of the context node that have <NAME> children. |
PLANET[NAME="Venus"] | Returns the <PLANET> children of the context node that have <NAME> children with text equal to "Venus". |
PLANET[@UNITS = "days"] | Returns all <PLANET> children of the context node that have a UNITS attribute with value "days". |
PLANET[6][@UNITS ="days"] | Returns the sixth <PLANET> child of the context node, only if that child has a UNITS attribute with value "days". Can also be written as PLANET[@UNITS ="days"][6]. |
PLANET[@COLOR and @UNITS] | Returns all the <PLANET> children of the context node that have both a COLOR attribute and a UNITSattribute. |
In XPath, you can locate data only at the node level. That's fine when you're working with software that handles XML data in terms of nodes, such as XSL transformations, but it's not good enough for all purposes. For example, a user working with a displayed XML document might be able to click the mouse at a particular point, or even select a range of XML content. (Note that such ranges might not start and end on node boundaries at all they might contain parts of various trees and subtrees.) To give you finer control over XML data, you can work with points and ranges in XPointer.
How do you define a point in the XPointer specification? To do so, you must use two items a node, and an index that can hold a positive integer or zero. The node specifies an origin for the point, and the index indicates how far the point you want is from that origin.
But what should the index be measured in terms of characters in the document, or number of nodes? In fact, there are two different types of points, and the index value you use is measured differently for those types.
When the origin node, also called the container node, of a point can have child nodes (which means that it's an element node or the root node), then the point is called a node-point.
The index of a node-point is measured in child nodes. Here, the index of a node-point must be equal to or less than the number of child nodes in the origin node. If you use an index of zero, the point is immediately before any child nodes. An index of 5 locates a point immediately after the fifth child node.
You can use axes with node-points: A node-point's siblings are the children of the container node before or after the node-point. Points don't have any children, however.
If the origin node can't contain any child nodes, only text, then the index is measured in characters. Points like these are called character-points.
The index of a character-point must be a positive integer or zero, and less than or equal to the length of the text string in the node. If the index is zero, the point is immediately before the first character; an index of 5 locates the point immediately after the fifth character. Character-points do not have preceding or following siblings, or children.
For example, you can treat <DOCUMENT> as a container node in this document:
<DOCUMENT> Hi there! </DOCUMENT>
In this case, there are nine character-points here, one before every character. The character-point at index 0 is right before the first character, H; the character-point at index 1 is right before the i; and so on.
In addition, you should note that the XPointer specification collapses all consecutive whitespace into a single space, so four spaces is the same as one space when calculating an index for a character-point. Also, you cannot place points inside a start tag, end tag, processing instruction, or comment, or inside any markup.
To create a point, you use the start-point() function with a predicate, like this:
start-point()[position()=10]
Here's an example; say that I wanted to position a point just before the e in the text in Mercury's <NAME> element:
<?xml version="1.0"?> <?xml-stylesheet type="text/xml" href="planets.xsl"?> <PLANETS> <PLANET> <NAME>Mercury</NAME> <MASS UNITS="(Earth = 1)">.0553</MASS> <DAY UNITS="days">58.65</DAY> <RADIUS UNITS="miles">1516</RADIUS> <DENSITY UNITS="(Earth = 1)">.983</DENSITY> <DISTANCE UNITS="million miles">43.4</DISTANCE><!--At perihelion--> </PLANET> . . .
In this case, I could use an expression like this to refer to the point right before the character e:
xpointer(/PLANETS/PLANET[1]/NAME/text()/start-point()[position() = 1])
Similarly, I can access the point right before the 6 in the text in Mercury's <DAY> element, 58.65 (which, of course, is text, not a number), this way:
xpointer(/PLANETS/PLANET[1]/DAY/text()/start-point()[position() = 3])
You can create ranges with two points, a start point and an end point, as long as they are in the same document and the start point is not after the end point. (If the start point and the end point are the same, the range is collapsed.) A range is all of the XML structure between those two points.
A range doesn't have to be a neat subsection of a document; it can extend from one subtree to another in the document, for example. All you need are a valid start point and a valid end point in the same document.
To create a range, you use two location paths, separated with the keyword to in the xpointer() function. For example, here's how to create a range that includes the whole word Mercury in planets.xml:
xpointer(/PLANETS/PLANET[1]/NAME/text()/start-point()[position() = 0] to /PLANETS/PLANET[1]/NAME/text()/start-point()[position() = 7])
Here's how to create a range that includes the entire text value in Mercury's <RADIUS> element, 1516:
xpointer(/PLANETS/PLANET[1]/RADIUS/text()/start-point()[position() = 0] to /PLANETS/PLANET[1]/RADIUS/text()/start-point()[position() = 4])
The XPointer specification adds a number of functions to those available in XPath to handle ranges:
Function | Description |
---|---|
range-to(location-set) | This function takes the locations you pass to it and returns a range that completely covers the location. For example, an element location is converted to a range by returning the element's parent as the origin node, the start point as the number of previous siblings the element has, and the end point as one greater than the start point. In other words, this function is intended to cover locations with ranges. |
range-inside(location-set) | This function returns a range or ranges covering each location in the argument location set. For example, if you pass an element location, the result is a range that encloses all that is inside the element. |
start-point(location-set) | This function returns a location set with start points in it. Those points are the start points of ranges that would cover the passed locations. For example, start-point(//PLANET[2]) would return the point immediately before the second <PLANET> element in the document, and start-point(//PLANET) would return a location set of the points just before each <PLANET> element. |
end-point(location-set) | This is the same as start-point(), except that it returns the corresponding endpoints of the ranges that cover the locations passed to it. |
The XPointer specification also includes a function for basic string matching, string-range(). This function returns a location set with one range for every nonoverlapping match to the search string. The match operation is case- sensitive.
You can also specify optional index and length arguments to specify how many characters after the match the range should start and how many characters should be in the range. Here's how you use string-range() in general:
string-range(location_set, string, [index, [length]])
Matching an Empty StringAn empty string, "", matches to the location immediately before any character, so you can use an empty string to match to the very beginning of any string. |
For example, this expression returns a location set containing ranges covering all matches to the word "Saturn":
string-range(/, "Saturn")
To extract a specific match from the location set returned, you use the [] operator. For example, this expression returns a range covering the second occurrence of "Saturn" in the document:
string-range(/, "Saturn")[2]
This expression returns a range covering the third occurrence of the word "Jupiter" in the <NAME> element of the sixth <PLANET> element in a document:
string-range(//PLANET[6]/NAME, "Jupiter")[3]
You can also specify the range you want to return using the index (which starts with a value of 1) and length arguments. For example, this expression returns a range covering the letters er in the third occurrence of the word "Jupiter" in the <NAME> element of the sixth <PLANET> element:
string-range(//PLANET[6]/NAME, "Jupiter", 6, 2)[3]
If you want to locate a specific point, you can create a collapsed (zero-length) range, like this:
string-range(//PLANET[6]/NAME, "Jupiter", 6, 0)[3]
Another way to get a specific point is to use the start-point() function, which returns the start point of a range:
start-point(string-range(//PLANET[6]/NAME, "Jupiter", 6, 2)[3])
Here's an expression that locates the second @ character in any text node in the document and the five characters following it:
string-range(/, "@", 1, 6)[2]
Because it's so common to refer to elements by location or ID, XPointer adds a few abbreviated forms of reference. Here's an example; suppose that you wanted to locate Venus's <DAY> element in planets.xml:
<?xml version="1.0"?> <?xml-stylesheet type="text/xml" href="planets.xsl"?> <PLANETS> <PLANET> <NAME>Mercury</NAME> <MASS UNITS="(Earth = 1)">.0553</MASS> <DAY UNITS="days">58.65</DAY> <RADIUS UNITS="miles">1516</RADIUS> <DENSITY UNITS="(Earth = 1)">.983</DENSITY> <DISTANCE UNITS="million miles">43.4</DISTANCE><!--At perihelion--> </PLANET> <PLANET> <NAME>Venus</NAME> <MASS UNITS="(Earth = 1)">.815</MASS> <DAY UNITS="days">116.75</DAY> <RADIUS UNITS="miles">3716</RADIUS> <DENSITY UNITS="(Earth = 1)">.943</DENSITY> <DISTANCE UNITS="million miles">66.8</DISTANCE><!--At perihelion--> </PLANET> . . .
You could do so with this rather formidable expression:
http://www.starpowdermovies.com/planets.xml# xpointer(/child::*[position()=1]/ child::*[position()=2]/child::*[position()=3])
As you know from Chapter 13, the child:: part is optional in XPath expressions, and the predicate [position() = x] can be abbreviated as [x]. In XPointer, you can abbreviate this still more, omitting the [ and ]. Here's the result, which is fairly compact:
http://www.starpowdermovies.com/planets.xml#1/2/3
When you see location steps made up of single numbers in this way, those location steps correspond to the location of elements.
In a similar way, you can use words as location steps, not just numbers, if those words correspond to ID values of elements in the document. For example, say that I give Venus's <PLANET> element the ID "Planet_Of_Love". (Here I'm assuming that this element's ID attribute is declared with the type ID in a DTD.)
<?xml version="1.0"?> <?xml-stylesheet type="text/xml" href="planets.xsl"?> <PLANETS> <PLANET> <NAME>Mercury</NAME> <MASS UNITS="(Earth = 1)">.0553</MASS> <DAY UNITS="days">58.65</DAY> <RADIUS UNITS="miles">1516</RADIUS> <DENSITY UNITS="(Earth = 1)">.983</DENSITY> <DISTANCE UNITS="million miles">43.4</DISTANCE><!--At perihelion--> </PLANET> <PLANET ID = "Planet_Of_Love"> <NAME>Venus</NAME> <MASS UNITS="(Earth = 1)">.815</MASS> <DAY UNITS="days">116.75</DAY> <RADIUS UNITS="miles">3716</RADIUS> <DENSITY UNITS="(Earth = 1)">.943</DENSITY> <DISTANCE UNITS="million miles">66.8</DISTANCE><!--At perihelion--> </PLANET> . . .
Now you could reach the <DAY> element in Venus's <PLANET> element like this:
http://www.starpowdermovies.com/planets.xml# xpointer(//child::*[id("Planet_Of_Love")]/child::*[position()=3]
However, there's also an abbreviated version that's much shorter. In this case, I use the fact that you can use an element's ID value as a location step, and the result looks like this:
http://www.starpowdermovies.com/planets.xml#Planet_Of_Love/3
As you can see, this form is considerably shorter.
In this example, I used the id() function; to use that function, you should declare ID attributes so that they have the type ID. However, not all documents have a DTD or schema, so XPointer enables you to specify alternative patterns using multiple XPointers. Here's how that might look in this case, where I specify two XPointers in one location step:
http://www.starpowdermovies.com/planets.xml# xpointer(id("Planet_Of_Love"))xpointer(//*[@id="Planet_Of_Love"])/3
If the first XPointer, which relies on the id() function, fails, the second XPointer is supposed to be used instead, and that one locates any element that has an attribute named ID with the required value. It remains to be seen how much of this syntax applications will actually implement.
That's it for XLinks and XPointers. As you can see, there's a lot of power here far more than with simple HTML hyperlinks. However, the XLink and XPointer standards have been proposed for quite a few years now, and there have been practically no implementations of them. Hopefully the future will bring more concrete results.
In the next chapter, I'm going to start looking at some popular XML applications in depth, starting with the most popular one of all: XHTML.
CONTENTS |