Subject: Re: [xsl] getting a label from a schema From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx> Date: Fri, 20 Apr 2001 09:25:00 +0100 |
Hi George, > I am very much an uneducated newbie that I find it difficult even to > phrase my question, but I cannot find the answer anywhere, so I am > asking. OK :) Just in general, if you're asking about XSLT it makes things a lot easier if you give a small example of the kind of output that you want from your input. I think from your description that given the following in the XML file: > My XML file includes: > <group type="Fieldx"> > <item>100.00</item> > <item>200.00</item> > </group> and the following in the XML Schema file that's associated with it: > Each item has a label associated with it by according to its name in > an .msd schema as in the following: > > <element name='Income1' type='Fieldx'> > <annotation> > <appinfo> > <xbrl:rollup to='income' weight='0' order='0'/> > <xbrl:label xml:lang='en'>Employment income</xbrl:label> > <xbrl:label xml:lang='fr'>Revenes d'emploi</xbrl:label> > </appinfo> > </annotation> > </element> You want two HTML files - one in English: Employment income: <select> <option>100.00</option> <option>200.00</option> </select> and one in French: Revenes d'emploi: <select> <option>100.00</option> <option>200.00</option> </select> or something along those lines? > 1. How do I get my XSLT stylesheet to make sure that all labels from > the schema are presented with the item values in an HTML doc, which > presents the XML data (even those whose value is zero)? The first thing is that you have to identify the schema file for the XML document. Now, you should have in your XML document an xsi:schemaLocation attribute or an xsi:noNamespaceSchemaLocation attribute that give the URL of your XML Schema. (If you don't have one of these, then you'll have to pass in the URL for the schema file with a stylesheet parameter instead.) It's not clear from your example what namespace the 'group' element is in, so I'll assume for now that it's in the null namespace (i.e. you haven't declared a default namespace with an xmlns attribute higher up the document). This makes things easier, because the xsi:noNamespaceSchemaLocation is just a URL that points to the schema for nodes in the null namespace. So, to get hold of the schema document, you need to declare the XML Schema Instance namespace: <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xbrl="your-xbrl-namespace" exclude-result-prefixes="xsi xbrl"> ... </xsl:stylesheet> You can then get the URL of the schema document with the XPath: /*/xsi:noNamespaceSchemaLocation and you can retrieve the schema document using the document() function: document(/*/xsi:noNamespaceSchemaLocation, /) [Note that the second argument there makes sure that the URL is resolved relative to the source XML that you're processing, rather than to the stylesheet.] You can hold this in a variable so that you can access it easily later on: <xsl:variable name="schema" select="document(/*/xsi:noNamespaceSchemaLocation, /)" /> [One thing I should point out here - the *only* schema information that you get through this method is the stuff that's actually held in that primary schema document. You *don't* get anything that's included or imported or redefined within the schema. That requires a lot more processing (something like the closure() function that Christian Nentwich has recently proposed would be useful here). You can expect that XSLT 2.0 and XPath 2.0 will give a lot more assistance on retrieving schema information which would also help here.] Now, when you're processing a group element, then you have to find the relevant part of the schema document that can give you the labels that you need. I'm a bit flummoxed by your XML Schema snippet, actually because it seems as though you're using the type of the group to retrieve the labels through the *type* of some random *element*. If the labels are associated with a *type*, then I would have expected them to be held within the type definition, something like: <complexType name="Fieldx"> <annotation> <appinfo> <xbrl:rollup to='income' weight='0' order='0'/> <xbrl:label xml:lang='en'>Employment income</xbrl:label> <xbrl:label xml:lang='fr'>Revenes d'emploi</xbrl:label> </appinfo> </annotation> ... </complexType> After all, there might be lots of elements in your schema that use the same type - how are you supposed to work out which one contains the correct labels? Anyway, it's probably easiest to get to the labels you want using a key that indexes them according to the type of the element that they're held within: <xsl:key name="labels" match="xbrl:label" use="ancestor::element/@type" /> With that key in place, then calling: key('labels', 'Fieldx') when the current node is in the schema (such as being the schema document root not) will give the labels you've defined in the schema. So, finally, we can construct the template for the group element: <xsl:template match="group"> <xsl:variable name="type" select="@type" /> <!-- this xsl:for-each just changes the current node to the schema document element --> <xsl:for-each select="$schema"> <xsl:value-of select="key('labels', $type)" /> </xsl:for-each> <select> <xsl:for-each select="item"> <option><xsl:value-of select="." /></option> </xsl:for-each> </select> </xsl:template> [Note that this only gets the *first* label.] > 2. How do I get my XSLT stylesheet to present the label and item > values only when the values are not equal to zero? 'When the values are not equal to zero' is ambiguous. Do you want to only display those item elements that are not equal to zero? In that case, you need: <xsl:for-each select="item[. != 0]"> ... </xsl:for-each> Do you want to only display anything if there are *no* item elements with a zero value? In that case, you need an xsl:if that tests whether it's not the case that there is an item child of the group element that has a zero value: <xsl:template match="group"> <xsl:if test="not(item = 0)"> ... </xsl:if> </xsl:template> Do you want to display it unless *all* the item elements have a zero value? In that case, you need an xsl:if that tests whether there is any item element without a zero value: <xsl:template match="group"> <xsl:if test="item != 0"> ... </xsl:if> </xsl:template> > 3. How do I indicate the language desired in my XML document? Well, first you need to tell the stylesheet which language you want to use, with a stylesheet parameter. You define the parameter at the top level of the stylesheet: <!-- default value is English --> <xsl:param name="lang" select="'en'" /> How you pass in the value of the parameter depends on the processor you're using and how you're using it. Have a look in your XSLT processor documentation. You can then use the $lang parameter to find only those labels whose language (as indicated by xml:lang) is equal to that $lang parameter. So when you're picking the label, instead of doing: <xsl:value-of select="key('labels', $type)" /> Do: <xsl:value-of select="key('labels', $type)[lang($lang)]" /> The lang() function returns true for nodes whose language (indicated through xml:lang) is equal to (or related to) the string passed as the parameter. It's better to use that than xml:lang = $lang because lang() does all sorts of clever stuff to do with resolving inherited languages and language subsets. I hope that helps, Jeni --- Jeni Tennison http://www.jenitennison.com/ XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
[xsl] getting a label from a schema, George Farkas | Thread | [xsl] XSLT FAQ? and really question, Jeremy E. Denton |
RE: [xsl] text output with some sig, Juergen Baier | Date | Re: [xsl] Transitive closure for XP, Francis Norton |
Month |