Стивен Холзнер - XSLT
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:template match="PLANETS">
<DOCUMENT>
<TITLE>
The Planets
</TITLE>
<PLANETS>
The first three planets are: <xsl:apply-templates select="PLANET"/>
</PLANETS>
</DOCUMENT>
</xsl:template>
<xsl:template match="PLANET">
<xsl:if test="NAME[not(text())]">
<xsl:message terminate="yes">
Each planet must have a name!
</xsl:message>
</xsl:if>
<xsl:value-of select="NAME"/>
<xsl:if test="position()!=last()">. </xsl:if>
<xsl:if test="position()=last()-1">and </xsl:if>
<xsl:if test="position()=last()">.</xsl:if>
</xsl:template>
</xsl:stylesheet>
Чтобы проверить работу этого кода, я задал один из элементов <NAME> пустым:
<?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><!--B перигелии-->
</PLANET>
<PLANET>
<NAME></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><!--B перигелии-->
</PLANET>
.
.
.
Вот как происходит обработка примера в Xalan:
C:planets>java org.apache.xalan.xslt.Process -IN planets.xml -XSL errors.xsl -OUT new.xml
file:///C:/XSL/w.xsl: Line 18: Column 38: Each planet must have a name!
XSLT Error (javax.xml.transform.TransformerException): Stylesheet directed termination
Если вы знакомы с конструкцией if в языках программирования, вы знаете, что инструкция if обычно сопровождается инструкцией else, которая выполняется при ложности условия в if. Но в XSLT нет элемента <xsl:else>. Для задания альтернативных ветвей выполнения XSLT служит элемент <xsl:choose>.
Элементы <xsl:choose>, <xsl:when> и <xsl:otherwise>
Элемент <xsl:choose> похож на оператор Java switch, который позволяет сравнивать значение условия с несколькими возможными вариантами.
У элемента <xsl:choose> нет атрибутов. Он содержит один или более элементов <xsl:when> и (не обязательно) один элемент <xsl:otherwise>, который в случае применения должен стоять последним.
Вот как это работает: в элемент <xsl:choose> заключаются элементы <xsl:when>, каждый с условием true/false. Применяется тело шаблона в первом элементе <xsl:when>, чье условие имеет значение true, все остальные не применяются. Последним элементом внутри элемента <xsl:choose> может быть элемент <xsl:otherwise> тело шаблона внутри этого элемента применяется, если ни одно из предыдущих условий <xsl:when> не имело значения true:
<xsl:choose>
<xsl:when test="expression1">
<!--template-body 1-->
</xsl:when>
<xsl:when test="expression">
<!-- template-body 2-->
</xsl:when>
<xsl:when test="expression3">
<!--template-body 3-->
</xsl:when>
<xsl:otherwise>
<!--template body 4-->
</xsl:otherwise>
</xsl:choose>
В предыдущем разделе для осуществления этого преобразования нам потребовалось три элемента <xsl:if>:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:template match="PLANETS">
<DOCUMENT>
<TITLE>
The Planets
</TITLE>
<PLANETS>
The first three planets are: <xsl:apply-templates select="PLANET"/>
</PLANETS>
</DOCUMENT>
</xsl:template>
<xsl:template match="PLANET">
<xsl:if test="NAME[not(text())]">
<xsl:message terminate="yes">
Each planet must have a name!
</xsl:message>
</xsl:if>
<xsl:value-of select="NAME"/>
<xsl:if test="position()!=last()">, </xsl:if>
<xsl:if test="position()=last()-1>and </xsl:if>
<xsl:if test="position()=last()">.</xsl:if>
</xsl:template>
</xsl:stylesheet>
Теперь то же самое можно сделать при помощи единственного элемента <xsl:choose>:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xml:output method="xml"/>
<xsl:template match="PLANETS">
<DOCUMENT>
<TITLE>
The Planets
</TITLE>
<PLANETS>
The first three planets are: <xsl:apply-templates select="PLANET"/>
</PLANETS>
</DOCUMENT>
</xsl:template>
<xsl:template match="PLANET">
<xsl:if test="NAME[not(text())]">
<xsl:message terminate="yes">
Each planet must have a name!
</xsl:message>
</xsl:if>
<xsl:value-of select="NAME"/>
<xsl:choose>
.
.
.
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Нам нужно проверить, в каком месте документа мы находимся, при помощи включения нескольких элементов <xsl:when>. У этого элемента только один атрибут:
• test (обязательный). Принимает логическое (Boolean) значение (true/false) проверяемого условия.
Элемент <xsl:when> содержит тело шаблона.
Атрибут проверки принимает значение true/false выражения, определяющего, будет ли применяться заключенное в элементе <xsl:when> тело шаблона или нет. Например, вот как я добавил элементы <xsl:when> с соответствующими знаками пунктуации для всех планет, кроме последней:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:template match="PLANETS">
<DOCUMENT>
<TITLE>
The Planets
</TITLE>
<PLANETS>
The first three planets are: <xsl:apply-templates select="PLANET"/>
</PLANETS>
</DOCUMENT>
</xsl:template>
<xsl:template match="PLANET">
<xsl:if test="NAME[not(text())]">
<xsl:message terminate="yes">
Each planet must have a name!
</xsl:message>
</xsl:if>
<xsl:value-of select="NAME"/>
<xsl:choose>
<xsl:when test="position()!=last()">, </xsl:when>
<xsl:when test="position()=last()-1">and </xsl:when>
.
.
.
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Эти два элемента <xsl:when> выбирают все элементы <PLANET> за исключением последнего, поэтому элемент <xsl:otherwise> можно применить для последнего элемента <PLANET>. Тело шаблона в этом элементе будет применено, если ни в одном элементе <xsl:when> в элементе <xsl:choose> условие не примет значение true.
У элемента <xsl:otherwise> нет атрибутов, и он содержит тело шаблона. Вот как это выглядит в листинге 5.4.
Листинг 5.4. Применение <xsl:choose><?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:template match="PLANETS">
<DOCUMENT>
<TITLE>
The Planets
</TITLE>
<PLANETS>
The first three planets are: <xsl:apply-templates select="PLANET"/>
</PLANETS>
</DOCUMENT>
</xsl:template>
<xsl:template match="PLANET">
<xsl:if test="NAME[not(text())]">
<xsl:message terminate="yes">
Each planet must have a name!
</xsl:message>
</xsl:if>
<xsl:value-of select="NAME"/>
<xsl:choose>
<xsl:when test="position()!=last()">, </xsl:when>
<xsl:when test="position()=last()-1">and </xsl:when>
<xsl:otherwise>.</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Вот как это работает; этот код дает тот же результат, что и код, проверяющий позицию элементов <PLANET> при помощи <xsl:if>: