How to handle eml2 'references' elements in XSLT transformations
Dan Higgins
higgins at nceas.ucsb.edu
Thu Jun 5 08:58:03 PDT 2003
Jing,
I finally got around to looking over your email and I think I see a
problem with your template.
It looks like it will work fine when a 'resources' element under a
'creator' node references another 'creator' node. However, the
'references' element can actually point to any node with a
ReponsibleParty subtree! i.e. if 'references' has an id that points to a
'contact' element rather than a 'creator', then when your template calls
itself recursively it will fail to match the'creator' and do nothing (I
think?).
Also, does the 'mode="resource"' do anything?
Dan
----
Jing Tao wrote:
>Hi, All:
>
>Dan's idea is great! Here is my solution for eml2 style sheet to handle
>references based on Dan's idea:
>
>First create a global variable id:
><xsl:variable name="ids" select="//*[@id!='']"/>
>
>Here is example template:
><xsl:template match="creator" mode="resource">
> <xsl:choose>
> <xsl:when test="references!=''">
> <xsl:variable name="ref_id" select="references"/>
> <xsl:variable name="references" select="$ids[@id=$ref_id]" />
> <xsl:apply-templates select="$references" mode="resource"/>
> </xsl:when>
> <xsl:otherwise>
> <tr><td colspan="2">
> <xsl:call-template name="party"/>
> </td></tr>
> </xsl:otherwise>
> </xsl:choose>
></xsl:template>
>
>This template will deal with creator element. If creator is not a
>reference (it will use the xsl:otherwise statement), it will call another
>template named party to do transformation. If it is a reference (it will
>use xsl:when statement), first assign the node set of references to variable
>"references" by statement <xsl:variable name="references"
>select="$ids[@id=$ref_id]" />. Then re-apply this template again by
>statement <xsl:apply-templates select="$references" mode="resource"/>. At
>this time, it will point to the referenced node sets and do
>transformation.
>
>Does somebody have comments about this?
>
>Thanks.
>
>Jing
>
>
>
>
>On Fri, 16 May 2003, Dan Higgins wrote:
>
>
>
>>Hi All,
>>
>>Below is a brief memo with some details of a method for handling
>>'references' elements in eml2 documents in XSLT transformations. (If you
>>don't care about XSLT transforms, Quit Reading Now!) This is a result of
>>my attempts at an eml2 to nbii translator. The current version of the
>>XSLT stylesheet (which is incomplete) is in the eml module of CVS
>>(eml/lib/eml2tonbii/eml2tonbii.xsl). Any better ideas would be appreciated.
>>
>>Dan
>>
>>-
>>Dan Higgins
>>16 May 2003
>>
>>How to handle eml2 'references' elements in XSLT transformations
>>
>>One of the features in eml2.0 that adds a great deal of flexibility is
>>the use of the 'references' element. This element can occur in a number
>>of places. It basic purpose is to allow the use of a "pointer" to
>>another part of the eml2 document so that information in a subtree need
>>not be duplicated. An obvious use is to avoid repeating the information
>>in a 'responsibleParty' module. If references to some individual occurs
>>in several places (e.g. as both the "Creator" and a 'Contact") then it
>>is desirable to only have the information in a single place. This not
>>only makes editing/revision easier and reduces the size of an eml2
>>document but also indicates that the descriptions are of the SAME party
>>(not someone with the same name).
>>
>>The mechanism for using "references" is to assign some 'id' attribute to
>>the head of a subtree at one location and then make this 'id' value the
>>content of a 'references' node elsewhere in the eml2 document where a
>>subtree of the same type (eg ResponsibleParty) occurs. A look at the
>>XMLSchema for eml2 shows that the 'references' element just appears as
>>alternate choice to some subtree. The 'id value' contained in the
>>references element should correspond to the 'id' attribute of some other
>>element in the eml document (and these assigned id values are assumed to
>>be unique).
>>
>>A common task that one may want to do with an eml2 document is to apply
>>an XSLT transformation to extract data or display its contents. One
>>example is to create an html display of the document's content. Another
>>is to convert the eml2 to another format like fgdc/nbii.
>>
>>Typically in such XSLT transformations, one want to copy data from some
>>Xpath in the original document to other location or structure. But how
>>does one handle the case where a 'references' node appears rather than
>>the subtree with the wanted data? The transformation can specify an
>>XPath down to some subnode and then continue down the subtree if the
>>informatin is inline, but how do you handle the case where only a
>>'references' node appears rather than the subtree? The following
>>describes one method that can be used. (There may be much better ones.)
>>
>>I started by defining an XSLT variable called 'ids' at the top of my
>>stylesheet.
>>
>> <xsl:variable name="ids" select="//*[@id!='']"/>
>>
>>The $ids variable is now a nodeset of all nodes in the document that
>>have 'id' attributes. One can then loook for nodes with a given id from
>>within this variable rather than having to search the entire document
>>every time a reference is encountered. [The ids are supposed to all be
>>unique, so the list should have all of them.]
>>
>>Now consider an example as shown in the XSLT fragment below which is
>>creating an element called 'citeinfo' and then trying to get information
>>from each "/eml:eml/dataset/creator" in an eml-document. The example
>>fragment creates an xsl:variable called 'cc'. When there is no
>>'references' child of the "/eml:eml/dataset/creator" element, the
>>variable is just set to a copy of the current node ("."). When
>>'./references' is NOT an empty string, a copy of the referenced subtree
>>is created by the
>>
>> <xsl:copy-of select="$ids[@id=$ref_id]"/>
>>
>>statement.
>>
>>----
>> <xsl:element name="citeinfo">
>> <xsl:for-each select="/eml:eml/dataset/creator">
>> <xsl:variable name="cc">
>> <xsl:choose>
>> <xsl:when test="./references!=''">
>> <xsl:variable name="ref_id" select="./references"/>
>> <!-- current element just references its contents
>> There should only be a single node with an id attribute
>> which matches the value of the references element -->
>> <xsl:copy-of select="$ids[@id=$ref_id]"/>
>> </xsl:when>
>> <xsl:otherwise>
>> <!-- no references tag, thus use the current node -->
>> <xsl:copy-of select="."/>
>> </xsl:otherwise>
>> </xsl:choose>
>> </xsl:variable>
>>
>> <xsl:element name="origin">
>> <!-- 'origin' should correspond to the name of the
>>'creator' RP in eml2 -->
>> <xsl:choose>
>> <xsl:when
>>test="xalan:nodeset($cc)//individualName/surName!=''">
>> <xsl:value-of
>>select="xalan:nodeset($cc)//individualName/surName"/>
>> </xsl:when>
>> ...
>>
>>----
>>
>>Once the varible $cc has been created, it should contain either the
>>current subtree or the one referenced in the 'references' element. The
>>above code fragment then creates an element named 'origin' and then
>>tries to get information from the children of the $cc variable to set
>>the value(s) of the 'origin' subtree. Note the statement
>>
>> <xsl:value-of select="xalan:nodeset($cc)//individualName/surName"/>
>>
>>The first part of this will be explained below, but basically the
>>expression before the '//' just gives the top node of the subtree in the
>>'$cc' variable, while the rest of the expression obtains the value of
>>the element 'surname' in the subtree path 'individualName/surName'.
>>
>>
>>Now consider the 'xalan:nodeset($cc) part of this path. I originally
>>thought that I could just use
>>
>> $cc//individualName/surName
>>
>>to specify the path, but in XSLT1.0, a variable is a NodeSet rather than
>>a tree. There is thus an error due to some type incompatibilties when
>>tries to specify child nodes. This problem is (reportedly) being
>>corrected in the newer XSLT specs, but in the meantime most of the XSLT
>>processors have an extension function that converts a NodeSet to a tree
>>so that expressions for child elements will operate. The expression
>>'xalan:nodeset($cc)' just converts the variable $cc to the correct type
>>for use in a path to get a subelement. This is a Xalan specific
>>function, but other XSLT engines have similar extensions.
>>-
>>
>>
>>
>>
>
>
>
--
*******************************************************************
Dan Higgins higgins at nceas.ucsb.edu
http://www.nceas.ucsb.edu/ Ph: 805-892-2531
National Center for Ecological Analysis and Synthesis (NCEAS)
735 State Street - Room 205
Santa Barbara, CA 93195
*******************************************************************
More information about the Eml-dev
mailing list