Tutorial on XSL

Download Report

Transcript Tutorial on XSL

Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
Using Extension Elements and
Extension Functions with XSLT
and XPath
Roger L. Costello
XML Technologies
1
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
Extension Elements
• The XSL processor understands how to
process xsl:template, xsl:apply-templates,
xsl:if, xsl:for-each, etc
– That is, it understands the vocabulary in the
XSL namespace
• XSL Processor implementers oftentimes
provide additional elements that you may
use in your stylesheet
– These extension elements will belong to a
namespace defined by the implementer
2
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
3
Example Extension Element:
instruct the xsl processor to
output to another file
• Many of the xsl processor implementers provide
an extension element that instructs the xsl
processor to output the contents of the element to
another file.
– Thus, your stylesheet can generate multiple output files!
XML
XSL
Processor
XSL
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
Vendor-specific
• Each implementor gives the extension
element a different name:
– saxon calls it: output
– xalan calls it: write
– xsl:result-document // xslt20
• example in xslt20
4
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
How to use an extension element
1. Declare the namespace that the extension element belongs to:
saxon:
xmlns:saxon="http://icl.com/saxon"
xalan:
xmlns:xalan="http://org.apache.xalan.xslt.extensions.Redirect"
2. Indicate that any element that is namespace qualified by the prefix
is an extension element, i.e., it has a specific meaning and should be
processed using the implementer's code:
saxon:
extension-element-prefixes="saxon"
xalan:
extension-element-prefixes="xalan"
3. Use the extension element:
saxon:
<saxon:output href="...">
-- anything in here will go to the file specified --</saxon:output>
xalan:
<xalan:write file="...">
-- anything in here will go to the file specified --</xalan:write>
5
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
6
Problem
• Write a stylesheet which outputs the
platinum members in one file, the gold
members in another file, and the third file is
an index to the other two files.
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
7
platinum.xml
FitnessCenter.xml
XSL
Processor
<PlatinumMembers href="platinum.xml"/>
<GoldMembers href="gold.xml"/>
new-FitnessCenter.xml
gold.xml
FitnessCenter.xsl
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
<xsl:copy-of select="xpath"/>
• This element instructs an xsl processor to
copy to the output file the element selected
by xpath, plus all its descendents.
<xsl:template match="Member">
<xsl:copy-of select="."/>
</xsl:template>
This instructs the xsl processor to copy everything from <Member> to </Member>
i.e., the Member element and all its descendents.
8
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
9
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:saxon="http://icl.com/saxon"
extension-element-prefixes="saxon"
version="1.0">
<xsl:output method="xml"/>
<xsl:template match="FitnessCenter">
<FitnessCenter>
<PlatinumMembers href="platinum.xml"/>
<saxon:output href="platinum.xml">
<PlatinumMembers>
<xsl:for-each select="Member[@level='platinum']">
<xsl:copy-of select="."/>
</xsl:for-each>
</PlatinumMembers>
</saxon:output>
<GoldMembers href="gold.xml"/>
<saxon:output href="gold.xml">
<GoldMembers>
<xsl:for-each select="Member[@level='gold']">
<xsl:copy-of select="."/>
</xsl:for-each>
</GoldMembers>
</saxon:output>
</FitnessCenter>
</xsl:template>
</xsl:stylesheet>
See extension-example01
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
Don’t forget extension-elementprefixes
• The extension-element-prefixes is used to
tell the xsl processor, "whenever you
encounter an element with any of these
prefixes listed here you are to treat it as an
extension element, and process it using the
implementer's code"
• If you fail to do so the xsl processor will
simply output the element literally (see
extension-example02)
10
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
Extension Functions
• We have seen some of the functions that
XSL provides: substring(), contains(),
substring-before, etc.
• Many xsl processor implementers provide
additional functions. You signify that a
function is an extension function by
namespace qualifying it.
11
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
Dynamic (run-time) Evaluation
• Many xsl processor implementers give you
an extension function that enables you to
dynamically evaluate an expression.
– That is, you can generate the expression on the
fly, or read it in from an external file.
• SAXON provides an extension function
called evaluate to do this.
12
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
FitnessCenter.xml
checkFitnessCenter.xml
13
XSL
Processor
results.xml
FitnessCenter.xsl
This file contains expressions that are dynamically evaluated against FitnessCenter.xml
Example: provide an xpath expression that ensures that each Member's level attribute is
either Platinum or Gold, and nothing else.
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
14
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:saxon="http://icl.com/saxon"
extension-element-prefixes="saxon"
version="1.0">
<xsl:output method="xml"/>
<xsl:variable name="tests"
select="document('checkFitnessCenter.xml')"/>
<xsl:template match="/">
<xsl:variable name="here" select="."/>
<FitnessCenter-results>
<xsl:for-each select="$tests//xpath">
<result>
<xsl:variable name="xpath" select="."/>
<xsl:value-of select="$xpath"/>
<xsl:for-each select="$here">
<xsl:choose>
<xsl:when test="saxon:evaluate($xpath)">
<xsl:text> SUCCEEDED</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text> FAILED</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:text>
</xsl:text>
</result>
</xsl:for-each>
</FitnessCenter-results>
</xsl:template>
</xsl:stylesheet>
Now any references is to elements
in checkFitnessCenter.xml
Takes us back to referencing
elements in FitnessCenter.xml
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
Using XSLT and XPath to
Transform XML Documents that
contain Namespaces
Roger L. Costello
XML Technologies
15
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
16
Problem
Suppose that the document that we are processing is using namespaces:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="FitnessCenter.xsl"?>
<FitnessCenter xmlns="http://www.gym.com">
<Member level="platinum">
<Name>Jeff</Name>
<Phone type="home">555-1234</Phone>
<Phone type="work">555-4321</Phone>
<FavoriteColor>lightgrey</FavoriteColor>
</Member>
</FitnessCenter>
Note that we have a default namespace declaration. Thus, FitnessCenter, Member,
Name, Phone, and FavoriteColor all belong to the http://www.gym.com namespace.
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
17
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html"/>
<xsl:template match="/">
<HTML>
<BODY>
<xsl:apply-templates/>
</BODY>
</HTML>
</xsl:template>
<xsl:template match="*">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="Member">
Your name is: <xsl:value-of
</xsl:template>
select="Name/text()"/>
<xsl:template match="text()">
<!-- Do nothing -->
</xsl:template>
</xsl:stylesheet>
(see namespaces-example01)
Output:
-- empty --
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
Why is the output empty?
<xsl:template match="Member">
Your name is: <xsl:value-of select="Name/text()"/>
</xsl:template>
This template does not match any element in the instance document!
This template matches on a Member element in no namespace.
However, in our instance document the Member element is in the
http://www.gym.org namespace, i.e.,
{http://www.gym.com}Member
18
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
19
Namespace Terminology
{http://www.gym.com}Member
Local name
Namespace URI
Expanded name = The combination of the namespace URI and the local name
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
Namespace Terminology (cont.)
<gym:FitnessCenter xmlns:gym="http://www.gym.com">
<gym:Member>
…
</gym:FitnessCenter>
<gym:Member>
prefix
20
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
21
local-name()
• This is a built-in function which returns a
string, corresponding to the local name of
the element.
<xsl:template match="*">
Local name = <xsl:value-of select="local-name(.)"/>
<xsl:apply-templates/>
</xsl:template>
Output:
Local name = FitnessCenter
Local name = Member
Local name = Name
Local name = Phone
Local name = Phone
Local name = FavoriteColor
(see namespaces-example02)
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
22
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html"/>
<xsl:template match="/">
<HTML>
<BODY>
<xsl:apply-templates/>
</BODY>
</HTML>
</xsl:template>
<xsl:template match="*">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="*[local-name()='Member']">
Your name is: <xsl:value-of
</xsl:template>
<xsl:template match="text()">
<!-- Do nothing -->
</xsl:template>
select=“*[local-name()=‘Name’]/text()"/>
Output:
Your name is: Jeff
</xsl:stylesheet>
(see namespaces-example03)
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
23
Alternatively
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:gym="http://www.gym.com"
version="1.0">
Declare the gym namespace
<xsl:output method="html"/>
<xsl:template match="/">
<HTML>
<BODY>
<xsl:apply-templates/>
</BODY>
</HTML>
</xsl:template>
<xsl:template match="*">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="gym:Member">
Your name is: <xsl:value-of select="gym:Name"/>
</xsl:template>
<xsl:template match="text()">
<!-- Do nothing -->
</xsl:template>
</xsl:stylesheet>
Match on the Member element
in the gym namespace
Select the Name element in
the gym namespace
(see namespaces-example04)
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
24
namespace-uri()
• This is a built-in function which returns a string
corresponding to the namespace URI of the node.
<xsl:template match="*">
Local name = <xsl:value-of select="local-name(.)"/>
Namespace URI = <xsl:value-of select="namespace-uri(.)"/>
<xsl:apply-templates/>
</xsl:template>
Output:
Local name = FitnessCenter
Namespace URI = http://www.gym.com
Local name = Member
Namespace URI = http://www.gym.com
Local name = Name
Namespace URI = http://www.gym.com
Local name = Phone
Namespace URI = http://www.gym.com
...
(see namespaces-example05)
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
name() Revisited
• We have seen the name() function before.
It returns the name of the node. But what
name does it return if the node is in a
namespace?
– Answer: it returns the element name and its
prefix (this is called the QName, for Qualified
Name)
25
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="FitnessCenter.xsl"?>
<gym:FitnessCenter xmlns:gym="http://www.gym.com">
<gym:Member level="platinum">
<gym:Name>Jeff</gym:Name>
<gym:Phone type="home">555-1234</gym:Phone>
<gym:Phone type="work">555-4321</gym:Phone>
<gym:FavoriteColor>lightgrey</gym:FavoriteColor>
</gym:Member>
</gym:FitnessCenter>
<xsl:template match="*">
Local name = <xsl:value-of select="local-name(.)"/>
Namespace URI = <xsl:value-of select="namespace-uri(.)"/>
Name = <xsl:value-of select="name(.)"/>
<xsl:apply-templates/>
</xsl:template>
26
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
Output:
Local name = FitnessCenter
Namespace URI = http://www.gym.com
Name = gym:FitnessCenter
Local name = Member
Namespace URI = http://www.gym.com
Name = gym:Member
Local name = Name
Namespace URI = http://www.gym.com
Name = gym:Name
Local name = Phone
Namespace URI = http://www.gym.com
Name = gym:Phone
Local name = Phone
Namespace URI = http://www.gym.com
Name = gym:Phone
Local name = FavoriteColor
Namespace URI = http://www.gym.com
Name = gym:FavoriteColor
27
(see namespaces-example06)
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
28
Identity transform - copying
namespace declarations
• Recall our identity transform stylesheet:
<xsl:template match="*">
<xsl:element name="{name(.)}">
<xsl:for-each select="@*">
<xsl:attribute name="{name(.)}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
Iterate through each
attribute and add them
as attributes onto the
element.
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
29
@* does not select namespace
declarations!
• The @* will only select non-namespace
declaration attributes. It will not select
namespace declaration attributes
<Library xmlns="http://www.library.org"
xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance"
id="Boston Public Library">
This will be selected by @*
These will not be selected by @*
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
Identity transformation for XML
documents containing namespaces?
• So how do we create a stylesheet that can
copy over namespace declarations, along
with the other attributes?
– Answer: use the <xsl:copy/> element
30
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
31
<xsl:copy/>
• This element will copy the current element
and all namespace declarations to the output
file.
• Shallow copy (copy current node)
• Cf: <xsl:copy-of />
– Deep copy (Copy current tree )
– copy all attributes and namespace nodes
– copy all descendants
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
32
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml"/>
<xsl:template match="* | @*">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
(see namespaces-example07)
The problem with this identity transform stylesheet is that it's not set up
to allow us to make changes to elements/attributes.
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
33
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml"/>
<xsl:template match="*">
<xsl:element name="{name(.)}">
<xsl:copy-of select="namespace::*" />
<xsl:for-each select="@*">
<xsl:attribute name="{name(.)}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Error! Attempting
to create an
element in a
namespace, but
the namespace
has not been
declared yet!
Copyright (c) [2002]. Roger L. Costello. All Rights Reserved.
34
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml"/>
<xsl:template match="*">
<xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
Simultaneously
<xsl:copy-of select="namespace::*" />
declare the
<xsl:for-each select="@*">
<xsl:attribute name="{name(.)}" namespace="{namespace-uri(.)}">element
and its
<xsl:value-of select="."/>
namespace
</xsl:attribute>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
Simultaneously
declare the
attribute
and its
namespace
</xsl:stylesheet>
(see namespaces-example08)