Главная » XSLT » Выполнение обхода в прямом порядке

0

Задача

Требуется рекурсивно обработать сначала сам элемент, а потом его потомков.

Решение

Все решения в этом рецепте имеют такой общий вид:

<xsl:template match="node()">

<!– Сделать что-то с текущим узлом –>

<!– Обработать потомков –> <xsl:apply-templates/> </xsl:template>

Обсуждение

Термин прямой порядок применяется, когда речь идет об обходе дерева таким об­разом, что сначала посещается корневой узел, а затем рекурсивно его дочерние узлы. Пожалуй, это самый распространенный способ обработки XML-документов. Из мно­гочисленных применений этой идиомы мы в настоящей главе рассмотрим только два. В последующих рецептах мы будем часто сталкиваться с таким способом обхода.

Рассмотрим упрощенную структурную схему организации (пример 5.2), в ко­торой B является дочерним элементом A, если работник, представленный элемен­том B, непосредственно подчиняется работнику, представленному элементом A. В примере 5.3 приведена программа, которая с помощью обхода в прямом порядке поясняет, кто кем руководит. В примере 5.4 показано, что печатается в результате работы этой программы.

Пример 5.3. Таблица стилей

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="text"/> <xsl:strip-space elements="*"/>

<xsl:template match="/employee" priority="10">

<xsl:value-of select="@name"/><xsl:text> глава компании. </xsl:text> <xsl:call-template name="HeShe"/><xsl:text> руководит </xsl:text> <xsl:call-template name="manages"/> <xsl:apply-templates/> </xsl:template>

<xsl:template match="employee[employee]">

<xsl:value-of select="@name"/><xsl:text> менеджер. </xsl:text> <xsl:call-template name="HeShe"/> <xsl:text> руководит </xsl:text> <xsl:call-template name="manages"/> <xsl:apply-templates/> </xsl:template>

<xsl:template match="employee">

<xsl:value-of select="@name"/><xsl:text> не имеет подчиненных. </xsl:text> <xsl:text>&#xa;</xsl:text>

</xsl:template>

<xsl:template name="HeShe"> <xsl:choose> <xsl:when test="@sex = ‘male’ ">

<xsl:text>OH</xsl:text> </xsl:when> <xsl:otherwise>

<xsl:text>Oна</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:template>

<xsl:template name="manages"> <xsl:for-each select="*"> <xsl:choose>

<xsl:when test="position() != last() and last() > 2">

<xsl:value-of select="@name"/><xsl:text>, </xsl:text> </xsl:when>

<xsl:when test="position() = last() and last() > 1"> <xsl:text> and </xsl:text:value-of

select="@name"/><xsl:text> и </xsl:text>

</xsl:when>

<xsl:when test="last() = 1">

<xsl:value-of select="@name"/><xsl:text>. </xsl:text> </xsl:when> <xsl:otherwise>

<xsl:value-of select="@name"/> </xsl:otherwise> </xsl:choose> </xsl:for-each> <xsl:text>&#xa;&#xa;</xsl:text> </xsl:template> </xsl:stylesheet>

Пример 5.4. Результат

Jil Michel глава компании. Она руководит Nancy Pratt, Jane Doe, и Mike Rosenbaum.

Nancy Pratt менеджер. Она руководит Phill McKraken и Ima Little.

Phill McKraken не имеет подчиненных.

Ima Little менеджер. Она руководит Betsy Ross.

Betsy Ross не имеет подчиненных.

Jane Doe менеджер. Она руководит Walter H. Potter и Wendy B.K. McDonald. Walter H. Potter не имеет подчиненных.

Wendy B.K. McDonald менеджер. Она руководит Craig F. Frye, Hardy Hamburg, и Rich Shaker.

Craig F. Frye не имеет подчиненных. Hardy Hamburg не имеет подчиненных. Rich Shaker не имеет подчиненных.

Mike Rosenbaum менеджер. Он руководит Cindy Post-Kellog и Oscar A. Winner.

Cindy Post-Kellog менеджер. Она руководит Allen Bran, Frank N. Berry, и Jack Apple.

Allen Bran не имеет подчиненных. Frank N. Berry не имеет подчиненных. Jack Apple не имеет подчиненных.

Oscar A. Winner менеджер. Он руководит Jack Nicklaus, Tom Hanks, и Susan Sarandon.

Jack Nicklaus менеджер. Он руководит R.P. McMurphy. R.P. McMurphy не имеет подчиненных.

Tom Hanks менеджер. Он руководит Forrest Gump и Andrew Beckett. Forrest Gump не имеет подчиненных. Andrew Beckett не имеет подчиненных.

Susan Sarandon менеджер. Она руководит Helen Prejean. Helen Prejean не имеет подчиненных.

Более серьезное применение обхода в прямом порядке – преобразование де­рева выражения в префиксную нотацию. В примере 5.5 приведен фрагмент

документа на языке MathML, а в примере 5.6 – программа его преобразования в Lisp-подобный синтаксис. В примере 5.7 представлен результат работы.

Пример 5.5. Фрагмент документа на языке MathML, представляющий уравнение x2 + 4x + 4 = 0

<apply> <eq/> <apply> <plus/> <apply> <power/> <ci>x</ci> <cn>2</cn> </apply> <apply> <times/> <cn>4</cn> <ci>x</ci> </apply> <cn>4</cn> </apply> <cn>0</cn> </apply>

Пример 5.5. Таблица стилей для преобразования фрагмента на языке MathML в префиксную нотацию

<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:strip-space elements="*"/>

<xsl:template match="apply">

<xsl:value-of select="local-name(*[1])"/> <xsl:text>(</xsl:text> <xsl:apply-templates/> <xsl:text>)</xsl:text>

<xsl:if test="following-sibling::*">,</xsl:if> </xsl:template>

<xsl:template match="ci|cn"> <xsl:value-of select="."/>

<xsl:if test="following-sibling::*">,</xsl:if> </xsl:template> </xsl:stylesheet>

Пример 5.7. Результат

eq(plus(power(x,2),times(4,x),4),0)

Конвертер MathML – не самый чистый пример обхода в прямом порядке, по­скольку в MathML математические выражения кодируются нетрадиционно. Но это безусловно пример идиомы «прямого порядка», так как первым обрабатывается элемент apply (и выводится имя первого дочернего элемента), а затем рекурсивно его потомки (с помощью элемента <xsl:apply-templates/>). Код, следующий за элементом <xsl:apply-templates/> балансирует скобки, вставляет в нуж­ные места запятые, но не выполняет дополнительных рекурсивных вызовов.

Мангано Сэл  XSLT. Сборник рецептов. – М.: ДМК Пресс, СПБ.: БХВ-Петербург, 2008. – 864 с.: ил.

По теме:

  • Комментарии