Kimber - Link targets - point at the title or at the container?
Subject: Re: Link targets - point at the title or at the container?
Date: 09 Mar 1998 00:00:00 GMT
From: "W. Eliot Kimber" <eliot@isogen.com>
Organization: ISOGEN International Corp.
Newsgroups: comp.text.sgml
Bob Thomas wrote:
> My inclination is to point at the container (Section) rather than at
> the
> title because I'm referring to what is inside of the element.
> Moreover,
> if I want to auto-insert the word Section during processing I won't
> have
> to check ancestory. However, this distinction seems to be somewhat
> esoteric for authors who reason that they want the title of the target
> section to go where the Xref element is, so why not just point to the
> title?
As others have pointed out, if the link is to the section, point to the
section. Style mechanisms should provide a way to reflect the title (or
some other identifying thing, such as list item number) at the point of
reference.
If you want to codify in your DTD declarations that the intended
presentation result is to reflect the title of the thing pointed to at
the point of reference, you can use the Value Reference Facility of the
HyTime architecture to declare this intent. If you have a generalized
value-reference-aware presentation system, it can just implement your
intent. If you don't, then you do whatever style thing you would have
done anyway.
The purpose of the value reference facility (clause 6.7.1 of ISO/IEC
10744:1997) is to let you declare that the value of some part of an
element is defined by reference to something else: the value is by
reference. You can use this for individual attributes of an element, the
content of an element, or for the entire element.
In the case of hyperlinks, the usual intent is that the content of the
hyperlink is some decsription of the thing linked to, such as the title.
In other words, the simplest form of cross reference is usually
something like:
<para>See <crossref refid="section-2">Section 2. Some More
Stuff</crossref> ...
Where "Section 2. Some More Stuff" is the title of the section whose ID
is "section-2":
<section id="section-2">
<title>Some More Stuff</title>
It's possible to create style sheets in most style languages to grab the
title and reflect it at the point of reference, so that you can have an
empty cross reference element and not have to worry about literally
copying the title:
<para>See <crossref refid="section-2"/> ...
Where the crossref element might be declared as:
<!ELEMENT crossref -- Effective content derived from target of reference
--
EMPTY
>
<!ATTLIST crossref
refid -- Pointer to target of cross reference --
IDREF
#REQUIRED
>
There's a problem here in that there's nothing in the element type
declaration that a processing program can look at to know that the
intent is to get the title of the target. This means that you are
dependent on humans always understanding and implementing the intent
correctly. If you are doing all the work yourself, fine. But if your DTD
will have a wider provenance, it's probably asking a lot, even if you
document your DTD well (because nobody ever reads the documentation, no
matter how good it is).
By putting some additional declarations in the DTD, you can make it
possible for automatic processors to implement your intent and more
likely that human implementors will understand what you meant (on the
presumption that they must look at the declarations even if they don't
read the documentation).
The declaration we need in this case is to say "the effective content of
this element type is the title of whatever it points at". That means we
need a way to say two things:
1. That we are defining the value of the effective content
2. How to find the title of the thing referenced.
The first task is handled by the HyTime-defined "valueref" attribute,
defined by the value reference facility. The valueref attribute binds a
part of an element to an attribute that points to the effective value of
the part. For the element's content, we need to say "the attribute X
points to the effective content of the element". Remember that this is
use by reference, that is, we're pointing at the thing we want to use as
the content.
In this case, we need to point to the title of the crossref target. That
means we need to declare an attribute to do this pointing. I'll get to
what the pointer actually is in a bit. For now, we'll just declare the
attribute:
<!ATTLIST crossref
refid
IDREF
#REQUIRED
ref-title -- Pointer to the title of the reference target --
CDATA -- Value is an address of some sort --
#FIXED "" -- Value can be fixed if we're clever. --
>
We now need to bind the "ref-title" attribute to the effective content
of the element, which we do with the HyTime-defined valueref attribute.
The keyword "#CONTENT" means "the effective content of this element":
<!ATTLIST crossref
refid
IDREF
#REQUIRED
ref-title -- Pointer to the title of the reference target --
CDATA -- Value is an address of some sort --
#FIXED ""-- Value can be fixed if we're clever. --
valueref -- Bind parts of the element to attributes that point
to their effective values. --
CDATA
#FIXED "#CONTENT ref-title"
>
The valueref attribute is read as "the effective content of this element
is addressed (pointed to) by the 'ref-title' attribute".
By "effective content" I mean the content that the *processing
application* considers the element to have, which may be different from
the syntactic content the SGML parser sees. In other words, after the
document is parsed into a processible form, the processing program
decides what it considers the element's content to be, which it could do
by any means it chooses (including built-in algorithms, style sheets, or
the value reference facility). In this case, we are declaring our intent
that the processing system consider the thing or things pointed at by
the ref-title attribute to be the effective content of the crossref
element.
Now we have to provide a value for the ref-title attribute, that is, a
pointer of some sort. We have a number of choices. We could use normal
ID references, which would work, but sort of miss the point and just
make things harder (now you have to manage two IDs and references for
each cross reference instead of one). We could use HyTime-defined
addressing methods. We could use TEI extended pointers or XML Xpointers.
We could use SDQL queries. We could define our own queries in our own
language.
All of these options have advantages and any would be an acceptable
choice.
If the intent is simply declarative for the purpose of better human
understanding of your intent, then you should pick the form that your
expected audience will most likely understand. My inclination in this
case is to go with published standards, which means SDQL for this type
of operation: anyone can read the DSSSL standard (ISO/IEC 10197:1996)
and figure out what your SDQL query means. If the audience is more
specialized, such as a Web audience, I'd probably go with Xpointers. If
my audience is a private development team, I'd probably define my own
query and just document it as I'd document any other part of the system
design.
If the intent is to enable automatic processing by generalized tools,
you need to pick the form that is mostly likely to be implemented. Right
now I'd go with XML Xpointers--seems like a pretty safe bet that they'll
be well documented and widely implemented. HyTime-defined addresses
would probably be a good choice as well (but I don't realistically
expect the Web world to embrace HyTime-defined addressing methods right
away--it will take a while for the Web world to reach the limit of what
you can do with Xpointers alone).
For this example, I'll use HyTime-defined addressing methods because the
form needed in this case is pretty easy to understand and I know how to
do it. I'll leave the Xpointer form as an exercise, but it would work
just as well and might be the better choice over all.
For simplicitly, let us assume that crossref elements will only be used
to point to elements that have titles as their first subelements. As
we've decided that a crossref always points to the the container
element, that suggests that we can address the title by addressing
relative to the container (which is what we'd do in a style sheet, for
example).
The HyTime-defined addressing method for this is the "relative location
address". It lets us address an element based on its genealogical
relationship to another element. In this case, we want the first child
of whatever is pointed to by the refid attribute. We get there in two
steps.
First, we provide a value for the ref-title attribute. This is our
reference location address specification:
<!ATTLIST crossref
refid
IDREF
#REQUIRED
ref-title -- Pointer to the title of the reference target --
CDATA -- Value is an address of some sort --
#FIXED "children 1 1" -- Get first child of location source --
valueref -- Bind parts of the element to attributes that point
to their effective values. --
CDATA
#FIXED "#CONTENT ref-title"
>
The value "children 1 1" says "get the first child from the list of
children". However, we haven't said the children of what. By default, it
would be the children of the crossref element, which is not what we
want.
What we want is the first child of the thing pointed to by the refid
attribute. Thus we need to bind the ref-title attribute to the refid
attribute. We do this with the "reference location source" (rflocsrc)
attribute:
<!ATTLIST crossref
refid
IDREF
#REQUIRED
ref-title -- Pointer to the title of the reference target --
CDATA -- Value is a relative location address specification --
#FIXED "children 1 1" -- Get first child of location source --
rflocsrc -- Bind an attribute to the attribute that addresses its
location source. --
CDATA
#FIXED "ref-title refid" -- Refid is location source for ref-title
--
valueref -- Bind parts of the element to attributes that point
to their effective values. --
CDATA
#FIXED "#CONTENT ref-title"
>
The rflocsrc (reference location source) attribute says that the
ref-title attribute is relative to whatever is pointed at by the
ref-title attribute. Thus, the ref-title attribute will get us the first
child of the target of the link.
We're pretty close to having a complete declaration. We still lack a
declaration of what the ref-title attribute is. Notice that although I
told you that it's a HyTime relative location, there is nothing in the
attribute declarations that tells you that. A generalized system could
not know for sure that ref-title really was a relative location address.
To solve this we use the HyTime-defined "location type" (loctype)
attribute, which binds attributes to their form of address. In this case
we need to indicate that the ref-title attribute is a HyTime relative
location:
<!ATTLIST crossref
refid
IDREF
#REQUIRED
ref-title -- Pointer to the title of the reference target --
CDATA -- Value is an address of some sort --
#FIXED "children 1 1" -- Get first child of location source --
loctype -- Declare addressing method of other attributes --
CDATA
#FIXED "ref-title relloc" -- ref-title is a relative location --
rflocsrc -- Bind an attribute to the attribute that addresses its
location source. --
CDATA
#FIXED "ref-title refid" -- Refid is location source for ref-title
--
valueref -- Bind parts of the element to attributes that point
to their effective values. --
CDATA
#FIXED "#CONTENT ref-title"
>
Very close now. The last thing we need to do is bind the crossref
element to the HyTime architecture, which is what defines the three
declarative attributes loctype, rflocsrc, and valueref. It we didn't
make this binding, then we wouldn't know for sure that these attributes
really are the ones defined by the HyTime standard (even though we might
be pretty sure they are). We do this binding by using the "HyTime"
attribute to associate the crossref element with some element defined by
the HyTime architecture:
<!ATTLIST crossref
refid
IDREF
#REQUIRED
ref-title -- Pointer to the title of the reference target --
CDATA -- Value is an address of some sort --
#FIXED "children 1 1" -- Get first child of location source --
loctype -- Declare addressing method of other attributes --
CDATA
#FIXED "ref-title relloc" -- ref-title is a relative location --
rflocsrc -- Bind an attribute to the attribute that addresses its
location source. --
CDATA
#FIXED "ref-title refid" -- Refid is location source for ref-title
--
valueref -- Bind parts of the element to attributes that point
to their effective values. --
CDATA
#FIXED "#CONTENT ref-title"
HyTime -- Bind crossref element to element form in HyTime
architecture --
NAME
#FIXED "hybrid" -- HyTime bridging element. Just makes crossref
"architectural" --
>
Here I've mapped the crossref element to the "hybrid" (HyTime bridge)
element form. This simply makes the crossref element "architectural"
with respect to the HyTime architecture without saying anything more
about the element. It allows a HyTime-aware processor to know that the
loctype, rflocsrc, and valueref attributes are its to process, without
imposing any additional HyTime-defined constraints or semantics on the
crossref element.
The declarations are now complete. A human looking at these declarations
can see that it has something to do with the HyTime architecture, can
look up the attributes in the standard
(http://www.ornl.gov/sgml/wg4/docs/n1920) and, with a little bit of
effort, figure out what the attributes mean and therefore what the
intent of the DTD designer is.
A HyTime-aware processor can look at these declarations and apply its
generalized processing to them to get the intended result. A processor
would decode the attributes as follows:
1. It sees that the element is mapped to something in the HyTime
architecture and therefore it needs to apply HyTime processing to it. It
sees that it is a HyBrid-form element, so it looks for HyTime-defined
attributes that are valid for hybrid.
2. It sees that there is a valueref attribute. It examines the attribute
to see that things are being gotten by reference. It sees that the
effective content ("#CONTENT") is by reference. It sees that the content
is addressed by the ref-title attribute.
3. It looks at the ref-title attribute. It sees that it is a CDATA
attribute. It knows the attribute is "referential" because the valueref
attribute told it so, but it doesn't know what form of reference the
ref-title attribute makes. (If ref-title had been declared as IDREF(S)
or ENTITY(IES) it would know.)
4. It looks for a loctype attribute, which it expects to find because
that's how HyTime has you declare the form of address used by a
particular attribute. It finds a loctype attribute and looks to see if
it names the ref-type attribute. It does. It sees that ref-type is
declared to be a relloc (relative location address).
5. This HyTime processor knows how to do relative locations, so it does
on (if it didn't know how to do relloc, it would have to issue a message
to the effect that it doesn't support the relloc facility and can't
complete the valueref proceessing). It knows that refential attributes
can use other attributes as their location source, so it looks for a
rflocsrc (reference location source) attribute. It finds one. It looks
to see if ref-type is named in it. It is. It sees that the refid
attribute is the location source for the ref-type attribute.
6. It looks at the refid attribute. It sees that it is declared as
IDREF. That's all it needs to know about refid, so it resolves the ID
reference.
7. It now has an element it can apply the relloc "child 1 1" to. It
does. It gets something, presumably a title element.
8. It uses the title element as the effective value of the crossref. A
style sheet applied to the crossref element formats the referenced title
element to produce the final display result (e.g., the text of the title
is presented at the point where the crossref element occurs, formatted
in whatever way hyperlink anchors are presented).
Note that instances of crossref elements don't change--you still just
specify the refid attribute like you always did. All we added was a
bunch of fixed attributes that serve to declare our intent as DTD
designers.
I didn't declare the crossref element as a HyTime hyperlink for two
reasons:
1. To keep this example as simple as possible
2. To emphasize that the use of the valueref facility has nothing to do
with whether or not it is used with hyperlink elements.
It just happens that in this case the element in the example is a
hyperlink, but it needn't be. It could just be an element that gets its
effective content by reference.
But since I brought it up, here's the crossref element declared to be a
HyTime hyperlink (here using the clink (contextual link) element form:
<!ATTLIST crossref
refid
IDREF
#REQUIRED
ref-title -- Pointer to the title of the reference target --
CDATA -- Value is an address of some sort --
#FIXED "children 1 1" -- Get first child of location source --
loctype -- Declare addressing method of other attributes --
CDATA
#FIXED "ref-title relloc" -- ref-title is a relative location --
rflocsrc -- Bind an attribute to the attribute that addresses its
location source. --
CDATA
#FIXED "ref-title refid" -- Refid is location source for ref-title
--
valueref -- Bind parts of the element to attributes that point
to their effective values. --
CDATA
#FIXED "#CONTENT ref-title"
HyTime -- Bind crossref element to element form in HyTime
architecture --
NAME
#FIXED "clink" -- HyTime contextual link element form --
HyNames -- Map HyTime-defined names to local names --
CDATA
#FIXED "linkend refid" -- Refid is interpreted as HyTime-defined
linkend --
>
The changes from the previous example are:
1. Changed HyTime form from hybrid to clink, making the element a HyTime
contextual hyperlink.
2. Mapped the local attribute name "refid" to the HyTime-defined
attribute
name "linkend", which is how clink-form elements point to their
targets.
Now a HyTime-aware processor will interpret the crossref element as a
hyperlink in addition to knowing how to get its effective content.
Without the valueref stuff, the declaration of crossref as a hyperlink
would be:
<!ATTLIST crossref
refid
IDREF
#REQUIRED
HyTime -- Bind crossref element to element form in HyTime
architecture --
NAME
#FIXED "clink" -- HyTime contextual link element form --
HyNames -- Map HyTime-defined names to local names --
CDATA
#FIXED "linkend refid" -- Refid is interpreted as HyTime-defined
linkend --
>
And you would again be left with the job of telling people and programs
how to get the effective content of crossref elements.
The HyTime facilities used in this example are:
- value reference facility, clause 6.7.1.,
http://www.ornl.gov/sgml/wg8/docs/n1920/html/clause-6.7.html#clause-6.7.1
- reference location address, clause 7.8,
http://www.ornl.gov/sgml/wg8/docs/n1920/html/clause-7.8.html
- hybrid (HyTime bridge), clause 6.6,
http://www.ornl.gov/sgml/wg8/docs/n1920/html/clause-6.6.html
- contextual link (clink), clause 8.2.2,
http://www.ornl.gov/sgml/wg8/docs/n1920/html/clause-8.2.html#clause-8.2.2
--
<Address HyTime=bibloc homepage="http://www.drmacro.com">
W. Eliot Kimber, eliot@isogen.com
Senior SGML Consulting Engineer, Highland Consulting
2200 North Lamar Street, Suite 230, Dallas, Texas 75202
+1-214-953-0004 +1-214-953-3152 (fax)
http://www.isogen.com (work)</Address>
![[Onward]](icon/next-1.png) |