• Изучаем XPath
  • Типы данных XPath
  • Наборы узлов XPath
  • Числа XPath
  • Строки XPath
  • Логические значения XPath
  • Создание путей расположения XPath
  • Шаги расположения XPath, часть 1: оси
  • Шаги расположения XPath, часть 2: условия узлов
  • Шаги расположения XPath, часть 3: предикаты
  • Применение осей XPath
  • Применение оси ancestor
  • Применение оси ancestor-or-self
  • Применение оси descendant
  • Применение оси descendant-or-self
  • Применение оси following
  • Применение оси following-sibling
  • Применение оси namespace
  • Применение оси parent
  • Применение оси preceding
  • Применение оси preceding-sibling
  • Применение оси self
  • Примеры путей расположения
  • Сокращенный синтаксис XPath
  • Проверка выражений XPath
  • XPath 2.0
  • Глава 7 

    Работа с XPath

    В главе 4 было объяснено, как создавать образцы выбора, которые можно использовать в атрибуте

    match
    таких элементов, как
    <xsl:template>
    . Образцы являются подмножеством полного языка XPath, и в этой главе будет рассмотрена полная версия XPath.

    Выражения XPath применимы в XSLT не только в образцах выбора, но и во многих других приложениях: в атрибуте

    select
    элементов
    <xsl:apply-templates>
    ,
    <xsl:value-of>
    ,
    <xsl:for-each>
    ,
    <xsl:param>
    ,
    <xsl:variable>
    ,
    <xsl:with-param>
    ,
    <xsl:copy-of>
    и
    <xsl:sort>
    , в шаблонах значений атрибутов, в атрибуте
    test
    элементов
    <xsl:if>
    и
    <xsl:when>
    , атрибуте
    value
    элемента
    <xsl:number>
    и в предикатах образцов выбора. На этот счет не может быть никаких сомнений: пока вы не знаете XPath, вы не знаете XSLT, и вся эта глава посвящена созданию выражений XPath и работе с ними.

    Фактически мы работали с выражениями XPath начиная с главы 1, в которой мы впервые познакомились с атрибутом

    select
    в элементах
    <xsl:apply-templates>
    и
    <xsl:value-of>
    :

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.0"

     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

     <xsl:template match="/PLANETS">

      <HTML>

       <HEAD>

        <TITLE>

         The Planets Table

        </TITLE>

       </HEAD>

       <BODY>

        <H1>

         The Planets Table

        </H1>

        <TABLE BORDER="2">

         <TR>

          <TD>Name</TD>

          <TD>Mass</TD>

          <TD>Radius</TD>

          <TD>Day</TD>

         </TR>

         <xsl:apply-templates/>

        </TABLE>

       </BODY>

      </HTML>

     </xsl:template>


     <xsl:template match="PLANET">

      <TR>

       <TD><xsl:value-of select="NAME"/></TD>

       <TD><xsl:apply-templates select="MASS"/></TD>

       <TD><xsl:apply-templates select="RADIUS"/></TD>

       <TD><xsl:apply-templates select="DAY"/></TD>

      </TR>

     </xsl:template>


     <xsl:template match="MASS">

      <xsl:value-of select="."/>

      <xsl:text> </xsl:text>

      <xsl:value-of select="@UNITS"/>

     </xsl:template>


     <xsl:template match="RADIUS">

      <xsl:value-of select="."/>

      <xsl:text> </xsl:text>

      <xsl:value-of select="@UNITS"/>

     </xsl:template>


     <xsl:template match="DAY">

      <xsl:value-of select="."/>

      <xsl:text> </xsl:text>

      <xsl:value-of select="@UNITS"/>

     </xsl:template>

    </xsl:stylesheet>

    Изучаем XPath

    Хотя мы уже знаем, например, что для обращения к текущему узлу можно присвоить «.» атрибуту

    select
    , «.» не является допустимым образцом выбора: это сокращение XPath для
    self::node()
    . Применение образцов выбора ограничено только двумя осями: ребенка и атрибута, но в XPath тринадцать осей, включая
    self
    . В этой главе мы рассмотрим все эти оси и приемы работы с ними.

    Говоря формально, XPath позволяет вам ссылаться на определенные разделы XML-документов — это язык, предназначенный для адресации различных частей таких документов. При помощи XPath вы указываете, с какой частью документа вы хотите работать. Вот что W3C говорит о XPath: 

    «Основная задача XPath — адресовать части документа XML. Для реализации этой первоочередной цели он также предоставляет основные средства оперирования строками, числами и логическими значениями. XPath обладает компактным, отличным от XML синтаксисом для облегчения его применения в идентификаторах URI и значениях атрибутов XML. XPath работает с абстрактной, логической структурой XML-документа, а не с его внешним синтаксисом. XPath получил свое имя благодаря тому, что для навигации по иерархической структуре XML-документа в нем используется нотация пути (path), как в идентификаторах URI».

    Эта цитата взята из спецификации XPath 1.0. Заметьте, что, хотя основной целью XPath является адресация частей XML-документов, он также поддерживает синтаксис для работы со строками, числами и логическими (true/false) значениями, который, как мы увидим, сам по себе очень полезен.

    В данный момент стандартом является XPath версии 1.0, но были выпущены требования для XPath 2.0. Пока еще нет рабочих проектов XPath 2.0, есть только список того, что W3C планирует туда включить. В конце главы будет приведен обзор этого списка. Первичные источники XPath вы найдете в двух местах:

    • спецификация XPath 1.0. XPath применяется для поиска и указания определенных разделов и элементов в документах XML для дальнейшей работы с ними. www.w3.org/TR/xpath;

    • требования XPath 2.0. XPath обновляется и в него включаются дополнительные средства поддержки XSLT 2.0 — в первую очередь поддержка схем XML. www.w3.org/TR/xpath20req.

    Вас могут заинтересовать следующие руководства по XPath:

    • http://www.zvon.org/xxl/XPathTutorial/General/examples.html;

    • http://www.pro-solutions.com/tutorials/xpath/.

    Рассмотренные нами до сих пор образцы выбора возвращали наборы узлов (node set), в которых можно было осуществить выбор или обработать набор в цикле, но XPath предоставляет более общие средства. Помимо наборов узлов, выражения XPath могут также возвращать числа, логические (true/false) значения и строки. Чтобы разобраться с XPath, необходимо разобраться с выражениями XPath. Только один вид выражения XPath (хотя и очень важный) возвращает наборы узлов, определяющие разделы документа. Как мы увидим, другие выражения XPath возвращают данные других видов.

    Полный синтаксис выражений XPath описан в спецификации XPath, и я приведу его здесь для справки. Как и в случае образцов выбора, для формального определения выражений XPath W3C использует нотацию расширенных форм Бэкуса-Наура (РБНФ). (Описание этой грамматики вы можете найти по адресу www.w3.org/TR/REC-xml, раздел 6.) В следующем списке приведена нужная нам нотация РБНФ:

    • 

    ::=
    означает «определяется как»;

    • 

    +
    означает «один или больше»,

    • 

    *
    означает «ноль или больше»;

    • 

    |
    означает «или»;

    • 

    -
    означает «не»;

    • 

    ?
    означает «не обязательно»;

    Также примите во внимание, что когда элемент заключен в одиночные кавычки, как

    'ancestor'
    или '
    ::
    ', это значит, что элемент должен появиться в выражении буквально (как "
    ancestor::PLANET
    "), — такие элементы называются литералами,
    literals
    . Ниже приведено полное формальное определение выражения XPath (здесь оно называется
    Expr
    ):

    Expr ::= OrExpr

    OrExpr ::= AndExpr | OrExpr 'or' AndExpr

    AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr

    EqualityExpr ::= Relational Expr | EqualityExpr '=' Relational Expr

     | EqualityExpr '!=' RelationalExpr

    RelationalExpr ::= AdditiveExpr | RelationalExpr '<' AdditiveExpr

     | RelationalExpr '>' AdditiveExpr | RelationalExpr '<=' AdditiveExpr

     | RelationalExpr '>=' AdditiveExpr

    AdditiveExpr ::= MultiplicativeExpr | AdditiveExpr '+' MultiplicativeExpr

     | AdditiveExpr '-' MultiplicativeExpr

    MultiplicativeExpr ::= UnaryExpr

     | MultiplicativeExpr

    MultiplyOperator ::= UnaryExpr

    | MultiplicativeExpr 'div' UnaryExpr | MultiplicativeExpr 'mod' UnaryExpr

    UnaryExpr ::= UnionExpr | '-' UnaryExpr

    MultiplyOperator ::= '*'

    UnionExpr ::= PathExpr | UnionExpr '|' PathExpr

    PathExpr ::= LocationPath | FilterExpr

     | FilterExpr '/' RelativeLocationPath | FilterExpr '//' RelativeLocationPath

    LocationPath ::= RelativeLocationPath | AbsoluteLocationPath

    AbsoluteLocationPath ::= '/' RelativeLocationPath? | AbbreviatedAbsoluteLocationPath

    RelativeLocationPath ::= Step | RelativeLocationPath '/' Step

     | AbbreviatedRelativeLocationPath

    AbbreviatedAbsoluteLocationPath ::= '//' RelativeLocationPath

    AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step

    Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep

    AxisSpecifier ::= AxisName '::' | AbbreviatedAxisSpecifier

    AxisName ::= 'ancestor' | 'ancestor-or-self' | 'attribute' | 'child' | 'descendant'

     | 'descendant-or-self' | 'following' | 'following-sibling' | 'namespace'

     | 'parent' | 'preceding' | 'preceding-sibling' | 'self'

    AbbreviatedAxisSpecifier ::= '@'?

    NodeTest ::= NameTest | NodeType '(' ')'

     | 'processing-instruction' '(' Literal ')'

    NameTest ::= '*' | NCName '*' | QName

    NodeType ::= 'comment' | 'text' | 'processing-instruction' | 'node'

    Predicate ::= '[' PredicateExpr ']'

    PredicateExpr ::= Expr

    FilterExpr ::= PrimaryExpr | FilterExpr Predicate

    PrimaryExpr ::= VariableReference | '(' Expr ')'

     | Literal | Number | FunctionCall

    VariableReference ::= '$' QName

    Number ::= Digits ('.' Digits?)? | Digits

    Digits ::= [0-9]+

    FunctionCall ::= FunctionName '(' ( Argument ( Argument )* )? ')'

    FunctionName ::= QName - NodeType

    Argument ::= Expr

    AbbreviatedStep := '.' | '..'

    Как видите, спецификация весьма объемна, она включает и обращения к функциям XPath (с которыми мы познакомимся в следующей главе). Лучший способ понять, как работают выражения XPath, — рассмотреть их по возвращаемым типам данных.

    Типы данных XPath

    В XPath существует четыре типа данных, а не только тип набора узлов, который должны возвращать образцы выбора:

    • наборы узлов;

    • логические значения;

    • числа;

    • строки.

    ФРАГМЕНТЫ РЕЗУЛЬТИРУЮЩЕГО ДЕРЕВА

    В XSLT 1.0 к типам данных XPath добавляются фрагменты результирующего дерева. Как говорилось в главе 4, фрагменты результирующего дерева представляют собой просто фрагменты дерева, которые можно присваивать переменным XSLT. Их поддержка была удалена из рабочего проекта XSLT 1.1, поэтому, скорее всего, они не будут включены в XSLT 2.0. Фрагменты результирующего дерева можно рассматривать как типы данных при помощи <xsl:variable>, что мы и увидим в главе 9.

    В следующих разделах мы по очереди рассмотрим эти типы данных.

    Наборы узлов XPath

    Как следует из имени, набор узлов (node set) является просто совокупностью узлов. Набор узлов может включать несколько узлов, единственный узел или быть пустым. Поскольку главная задача XPath — определять место разделов документов, постольку возвращающие наборы узлов выражения XPath являются наиболее популярными типами выражений. Например, выражение XPath

    child::PLANET
    возвращает набор узлов из всех элементов
    <PLANET>
    , дочерних для контекстного узла. Выражение
    child::PLANET/child::NAME
    возвращает набор узлов из всех элементов
    <NAME>
    , дочерних для элементов
    <PLANET>
    контекстного узла. Выражения XPath такого рода называются путями расположения, location path (W3C называет их «самой важной конструкцией» в XPath), и существенная часть этой главы будет посвящена разъяснению путей расположения.

    Чтобы выбрать узел или узлы из набора узлов или обработать их, вы можете воспользоваться следующими функциями XPath для работы с наборами узлов, которые впервые встретились нам в главе 4 (и которые мы более подробно рассмотрим в следующей главе):

    • 

    count(node-set)
    . Эта функция возвращает количество узлов в наборе. Если опустить параметр «набор узлов», функция будет применена к контекстному узлу;

    • 

    id(string ID)
    . Эта функция возвращает набор узлов из элемента, чей ID удовлетворяет строке, переданной функции в качестве параметра, или пустой набор узлов, если ни у какого элемента нет указанного ID. Можно указать несколько идентификаторов, разделенных символами-разделителями, — в таком случае функция вернет набор узлов из элементов с этими идентификаторами;

    • 

    last()
    . Возвращает номер последнего узла в наборе;

    • 

    local-name(node-set)
    . Возвращает локальное имя первого узла в наборе. Если опустить параметр «набор узлов», функция будет применена к контекстному узлу;

    • 

    name(node-set)
    . Возвращает полностью определенное имя первого узла в наборе. Если опустить параметр «набор узлов», функция будет применена к контекстному узлу;

    • 

    namespace-uri(node-set)
    . Возвращает URI пространства имен первого узла в наборе. Если опустить параметр «набор узлов», функция будет применена к контекстному узлу;

    • 

    position()
    . Возвращает позицию контекстного узла в контекстном наборе узлов (начиная с 1).

    В следующем примере (из главы 6) для подсчета количества узлов в наборе применяется функция

    count
    . В этом случае набор узлов состоит из всех элементов
    <PLANET>
    в
    planets.xml
    , и я получил его при помощи пути расположения «
    \\PLANET
    » (который как путь расположения также является выражением XPath):

    <xsl:stylesheet

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

     <xsl:output method="xml" indent="yes"/>

     <xsl:template match="*">

      <xsl:copy>

       <xsl:apply-templates/>

      </xsl:copy>

     </xsl:template>


     <xsl:template match="PLANET">

      <xsl:copy use-attribute-sets="numbering">

       <xsl:apply-templates/>

      </xsl:copy>

     </xsl:template>


     <xsl:attribute-set name="numbering">

      <xsl:attribute name="number"><xsl:number/></xsl:attribute>

      <xsl:attribute name="total">

       <xsl:value-of select="count(//PLANET)"/>

      </xsl:attribute>

     </xsl:attribute-set>

    </xsl:stylesheet>

    Ниже показан результат; заметьте, что у каждого элемента

    <PLANET>
    есть оба атрибута,
    number
    и
    total
    , и атрибут
    total
    содержит общее число элементов
    <PLANET>
    в документе:

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

    <PLANETS>

     <PLANET number="1" total="3">

      <NAME>Mercury</NAME>

      <MASS>.0553</MASS>

      <DAY>58.65</DAY>

      <RADIUS>1516</RADIUS>

      <DENSITY>.983</DENSITY>

      <DISTANCE>43.4</DISTANCE>

     </PLANET>

     <PLANET number="2" total="3">

      <NAME>Venus</NAME>

      <MASS>.815</MASS>

      <DAY>116.75</DAY>

      <RADIUS>3716</RADIUS>

      <DENSITY>.943</DENSITY>

      <DISTANCE>66.8</DISTANCE>

     </PLANET>

     <PLANET number="3" total="3">

      <NAME>Earth</NAME>

      <MASS>1</MASS>

      <DAY>1</DAY>

      <RADIUS>2107</RADIUS>

      <DENSITY>1</DENSITY>

      <DISTANCE>128.4</DISTANCE>

     </PLANET>

    </PLANETS>

    Среди функций для работы с наборами узлов в особенности обратите внимание на функции

    name
    и
    local-name
    . С их помощью можно определить имя текущего элемента: например, если текущим элементом является
    <DAY>
    ,
    local-name
    вернет
    DAY
    . Следующая таблица стилей демонстрирует, для чего это может понадобиться; в ней я использую такие теги, как
    <PLANETS>
    ,
    <PLANET>
    и
    <DATA>
    , в качестве элементов буквального результата:

    <?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">

      <PLANETS>

       <xsl:for-each select="PLANET">

        <PLANET>

         <xsl:for-each select="*">

          <DATA>

           <xsl:value-of select="."/>

          </DATA>

         </xsl:for-each>

        </PLANET>

       </xsl:for-each>

      </PLANETS>

     </xsl:template>

    </xsl:stylesheet>

    Однако в таком случае разметка трактуется как простой текст. Вместо этого можно создать новые элементы при помощи

    <xsl:element>
    , определяя имена контекстных узлов через
    local-name
    :

    <?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">

      <xsl:element name="{local-name(.)}">

       <xsl:for-each select="PLANET">

        <xsl:element name="{local-name(.)}">

         <xsl:for-each select="*">

          <xsl:element name="DATA">

           <xsl:value-of select="."/>

          </xsl:element>

         </xsl:for-each>

        </xsl:element>

       </xsl:for-each>

      </xsl:element>

     </xsl:template>

    </xsl:stylesheet>

    Ряд пишущих об XSLT авторов рассматривает выражения XSLT только как выражения, возвращающие наборы узлов. Но выражения XPath возвращают также логические значения, числа и строки, которые используются в элементах

    <xsl:param>
    , <xsl:with-param>,
    <xsl:number>
    ,
    <xsl:value-of>
    ,
    <xsl:sort>
    , шаблонах значений атрибутов и предикатах путей расположения. В предыдущем примере для вставки в документ числа я присвоил атрибуту
    select
    элемента
    <xsl:value-of>
    выражение XPath
    count(//PLANET)
    , которое возвращает не набор узлов, а число. Сейчас мы как раз перейдем к обработке чисел при помощи выражений XPath.

    Числа XPath

    В XPath числа хранятся в формате чисел с плавающей точкой двойной точности. В соответствии с формальным определением, числа XPath должны храниться в формате 64-разрядных чисел с плавающей точкой двойной точности IEEE 754, и все числа хранятся как числа с плавающей точкой двойной точности.

    В XPath можно выполнять следующие операции над числами, как мы уже видели в главе 4 при обсуждении предикатов XPath:

    • 

    +
    сложение;

    • 

    -
    вычитание;

     

    *
    умножение;

    • 

    div
    деление (символ /, соответствующий делению в других языках, в XML и XPath уже занят);

    • 

    mod
    возвращает значение деления по модулю двух чисел (остаток после деления первого числа на второе).

    Например, элемент

    <xsl:value-of select="15+75"/>
    вставит в выходной документ строку «
    90
    ». В следующем примере выбираются все планеты, чей день (измеренный в днях Земли), умноженный на расстояние планеты от Солнца (измеренное в миллионах миль), больше, чем 60 000:

    <xsl:template match="PLANETS">

     <HTML>

      <BODY>

       <xsl:apply-templates select="PLANET[DAY * MASS > 60000]"/>

      </BODY>

     </HTML>

    </xsl:template>

    XPath также поддерживает следующие функции работы с числами:

    • 

    ceiling()
    . Возвращает наименьшее целое, большее, чем переданное функции число;

    • 

    floor()
    . Возвращает наибольшее целое, меньшее, чем переданное функции число;

    • 

    round()
    . Округляет переданное число до ближайшего целого;

    • 

    sum()
    . Возвращает сумму переданных функции чисел.

    Например, среднее расстояние от Солнца (в миллионах миль) планет в

    planets.xml
    можно найти таким способом:

    <?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">

      <HTML>

       <BODY>

        The average planetary distance from the Sun is:

        <xsl:value-of select="sum(child::PLANET/child:DISTANCE) div count(child::PLANET)"/>

       </BODY>

      </HTML>

     </xsl:template>

    </xsl:stylesheet>

    Строки XPath

    В XPath строки по умолчанию состоят из символов Unicode. Как мы уже видели в главе 4 при обсуждении выражений XPath в предикатах выбора, существует ряд функций, специально предназначенных для работы со строками (более подробно они будут изучаться в следующей главе):

    • 

    concat(string string1, string string2,...)
    . Возвращает конкатенацию (объединение) всех строк;

    • 

    contains(string string1, string string2)
    . Возвращает
    true
    (истину), если первая строка содержит (contains) вторую строку;

    • 

    format-number(number number1, string string2, string string3)
    . Возвращает строку, содержащую число
    number1
    в виде форматированной строки, используя
    string2
    в качестве форматирующей строки (форматирующие строки создаются так же, как для метода Java
    java.text.DecimalFormat
    ) и
    string3
    как возможную строку локализации;

    • 

    normalize-space(string string1)
    . Возвращает строку
    string1
    после отбрасывания лидирующих и завершающих символов-разделителей и замены нескольких последовательных разделителей на один пробел;

    • 

    starts-with(string string1, string string2)
    . Возвращает истину, если первая строка начинается (starts with) со второй строки;

    • 

    string-length(string string1)
    . Возвращает количество символов в строке
    string1
    ;

    • 

    substring(string string1, number offset number length)
    . Возвращает
    length
    символов из строки, начиная со смещения
    offset
    ;

    • 

    substring-after(string string1, string string2)
    . Возвращает часть строки
    string1
    после первого вхождения
    string2
    ;

    • 

    substring-before(string string1, string string2)
    . Возвращает часть строки
    string1
    до первого вхождения строки
    string2
    ;

    • 

    translate(string string1, string string2, string string3)
    . Возвращает строку
    string1
    , в которой все вхождения символов в строке str
    i
    ng2 заменены на соответствующие символы в строке
    string3
    .

    В листинге 7.1 я ищу слово «miles» во всех атрибутах, и если оно встречается, добавляю в результирующий документ текст «You should switch to kilometers.» (Нужно перевести в километры.).

    Листинг 7.1. Поиск текста в атрибутах

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.0"

     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

     <xsl:template match="/PLANETS">

      <HTML>

       <HEAD>

        <TITLE>

         The Planets Table

        </TITLE>

       </HEAD>

       <BODY>

        <H1>

         The Planets Table

        </H1>

        <TABLE BORDER="2">

         <TR>

          <TD>Name</TD>

          <TD>Mass</TD>

          <TD>Radius</TD>

          <TD>Day</TD>

          <TD>Distance</TD>

         </TR>

         <xsl:apply-templates/>

        </TABLE>

       </BODY>

      </HTML>

     </xsl:template>


     <xsl:template match="PLANET">

      <TR>

       <TD><xsl:value-of select="NAME"/></TD>

       <TD><xsl:apply-templates select="MASS/></TD>

       <TD><xsl:apply-templates select="RADIUS"/></TD>

       <TD><xsl:apply-templates select="DAY"/></TD>

       <TD><xsl:apply-templates select="DISTANCE"/></TD>

      </TR>

     </xsl:template>


     <xsl:template match="MASS">

      <xsl:value-of select="."/>

      <xsl:text> </xsl:text>

      <xsl:value-of select="@UNITS"/>

     </xsl:template>


     <xsl:template match="RADIUS">

      <xsl:value-of select="."/>

      <xsl:text> </xsl:text>

      <xsl:value-of select="@UNITS"/>

     </xsl:template>


     <xsl:template match="DAY">

      <xsl:value-of select="."/>

      <xsl:text> </xsl:text>

      <xsl:value-of select="@UNITS"/>

     </xsl:template>


     <xsl:template match="DISTANCE">

      <xsl:value-of select="."/>

      <xsl:text> </xsl:text>

      <xsl:value-of select="@UNITS"/>

     </xsl:template>


     <xsl:template match="//*[contains(@UNITS, 'miles')]">

      <xsl:value-of select="."/>

      <xsl:text> </xsl:text>

      <xsl:text>You should switch to kilometers.</xsl:text>

     </xsl:template>

    </xsl:stylesheet>

    Вот результирующий документ:

    <HTML>

     <HEAD>

      <TITLE>

       The Planets Table

      </TITLE>

     </HEAD>

     <BODY>

      <H1>

       The Planets Table

      </H1>

      <TABLE BORDER="2">

       <TR>

        <TD>Name</TD>

        <TD>Mass</TD>

        <TD>Radius</TD>

        <TD>Day</TD>

        <TD>Distance</TD>

       </TR>

       <TR>

        <TD>Mercury</TD>

        <TD>.0553 (Earth = 1)</TD>

        <TD>1516 You should switch to kilometers.</TD>

        <TD>58.65 days</TD>

        <TD>43.4 You should switch to kilometers.</TD>

       </TR>

       <TR>

        <TD>Venus</TD>

        <TD>.815 (Earth = 1)</TD>

        <TD>3716 You should switch to kilometers.</TD>

        <TD>116.75 days</TD>

        <TD>66.8 You should switch to kilometers.</TD>

       </TR>

       <TR>

        <TD>Earth</TD>

        <TD>1 (Earth = 1)</TD>

        <TD>2107 You should switch to kilometers.</TD>

        <TD>1 days</TD>

        <TD>128.4 You should switch to kilometers.</TD>

       </TR>

      </TABLE>

     </BODY>

    </HTML>

    Помимо работы с наборами узлов, числами и строками, можно работать и с логическими значениями (true/false).

    Логические значения XPath

    Логические (Boolean) выражения XPath вычисляются либо в истину (true), либо в ложь (false), и обычно они используются только в предикатах. Для чисел ноль принимается за ложь, другие значения — за истину. Пустая строка, "", также считается ложью, все остальные строки — истиной.

    Для генерации логических результатов true/false в XPath можно применять ряд логических операций, как мы видели в обзоре в главе 4:

    • 

    !=
    означает «не равно»;

    • 

    <
    означает «меньше, чем» (в документах XML используйте
    &lt;
    );

    • 

    <=
    означает «меньше или равно» (в документах XML используйте
    &lt;=
    );

    • 

    =
    означает «равно» (программисты на С, С++, Java и JavaScript, обратите внимание: эта операция пишется как один знак =, а не два);

    • 

    >
    означает «больше, чем»;

    • 

    >=
    означает «больше или равно».

    Для связи логических выражений логическими операциями And и Or используются ключевые слова

    and
    и
    or
    , слово
    not
    инвертирует логический смысл выражения, как в следующем примере, где я выбираю все элементы
    <PLANET>
    , кроме первого и последнего:

    <xsl:template match="PLANET[not(position() = 1) and not(position() = last())]">

     <xsl:value-of select="."/>

    </xsl:template>

    Следующий пример уже встречался нам в главе 5, он использует логическую операцию

    not
    и операции
    =
    и
    !=
    :

    <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>

    Кроме того, имеется функция

    true
    , всегда возвращающая истину, и функция
    false
    , всегда возвращающая ложь. Есть также функция
    lang
    , при помощи которой вы можете проверить язык, установленный в атрибуте документа
    xml:lang
    : эта функция возвращает истину, если язык, который вы передали в эту функцию, такой же, как и установленный в документе язык.

    Как вы видели, существуют все виды выражений XPath, в том числе возвращающие узлы, числа, строки и логические значения. Наиболее важным типом выражений XPath является путь расположения; для создания путей расположена XPath первоначально и задумывался, поэтому оставшаяся часть главы будет посвящена работе с ними.

    Создание путей расположения XPath

    Вы уже знакомы со взглядом на документы с позиции XPath; например, в XPath определено семь типов узлов документа:

    • Корневой узел. Самое начало документа. Этот узел представляет в XPath весь документ;

    • Узлы элементов. Представляют элементы в деревьях XPath, обозначенные открывающим и соответственным закрывающим тегами или единственным пустым тегом элемента;

    • Узлы атрибутов. Значение атрибута после раскрытия ссылок на сущность и отбрасывания окружающих символов-разделителей;

    • Узлы комментариев. Текст комментариев, не включая

    <!--
    и
    -->
    ;

    • Узлы пространств имен. Объявление пространства имен. В XPath узел пространства имен добавляется во все элементы для каждого активного пространства имен, включая пространства имен по умолчанию;

    • Узлы инструкций обработки. Содержат текст инструкции обработки, не включая

    <?
    и
    ?>
    ;

    • Текстовые узлы. Текст PCDATA. Текстовые узлы по умолчанию в XPath нормализованы, поэтому расположенные рядом текстовые узлы немедленно объединяются.

    Для задания узла или набора узлов в XPath служит путь расположения (location path). Путь расположения, в свою очередь, состоит из одного или более шагов расположения (location step), также называемых просто шагами, разделенных / или //. Если путь расположения начинается с /, он называется абсолютным путем расположения, поскольку путь задается от корневого узла; иначе путь называется относительным, начинаясь от контекстного узла.

    Шаги расположения, строительные блоки путей расположения, во многом похожи на образцы шага (step patterns), формирующие образцы выбора, которые мы видели в главе 4. В частности, шаг расположения образован из оси (axis), условия узла (node test) и предикатов (которых может и не быть) по такому образцу:

    axis::nodetest[predicate]
    . Например, в выражении
    ancestor::NAME[position() > 100]
    ,
    ancestor
    — это имя оси,
    NAME
    — условие узла и
    [position() >100]
    — предикат. (Предикат сам содержит законченное выражение XPath, обычно возвращающее логическое значение.) Пути расположения создаются при помощи одного или более шагов расположения, таких как
    /descendant::PLANET/child::NAME
    , который выбирает все элементы
    <NAME>
    с родителем
    <PLANET>
    .

    Шаги XPath похожи на образцы шага из главы 4, так как общий их вид одинаков —

    axis::nodetest[predicate]
    — но в данном случае нужно рассмотреть значительно больше материала. Например, осей теперь тринадцать, а не две.

    Шаги расположения XPath, часть 1: оси

    В пути расположения

    ancestor::NAME
    , адресующем элемент
    <NAME>
    , который является предком контекстного узла,
    ancestor
    выступает осью. XPath поддерживает много различных осей, ниже приведен полный список:

    • ось

    ancestor
    содержит предков (ancestor) контекстного узла, то есть родителей контекстного узла, родителей этих родителей и т.д., вплоть до корневого узла (включая его);

    • ось

    ancestor-or-self
    содержит контекстный узел и его предков;

    • ось

    attribute
    содержит атрибуты контекстного узла;

    • ось

    child
    содержит детей контекстного узла;

    • ось

    descendant
    содержит потомков (descendant) контекстного узла, то есть его детей, детей этих детей и т.д.;

    • ось

    descendant-or-self
    содержит контекстный узел и его потомков;

    • ось

    following
    содержит все узлы в том же документе, такие же, как контекстный узел, встретившиеся после контекстного узла;

    • ось

    following-sibling
    содержит всех последующих братьев контекстного узла. «Брат» — узел, расположенный на том же уровне, что и контекстный узел;

    • ось

    namespace
    содержит узлы пространств имен контекстного узла;

    • ось

    parent
    содержит родителя контекстного узла;

    • ось

    preceding
    содержит все узлы до контекстного узла;

    • ось

    preceding-sibling
    содержит всех предшествующих «братьев» контекстного узла;

    • ось

    self
    содержит контекстный узел.

    В следующем примере шаблона я воспользовался осью

    descendant
    для выбора потомков контекстного узла, куда входят дочерние узлы, узлы-внуки, узлы-правнуки и т.д.:

    <xsl:template match="PLANET">

     <DATA>

      <NAME>

       <xsl:value-of select="descendant::NAME"/>

      </NAME>

      <MASS>

       <xsl:value-of select="descendant::MASS"/>

      </MASS>

      <DAY>

       <xsl:value-of select="descendant::DAY"/>

      </DAY>

     </DATA>

    </xsl:template>

    В этой главе мы рассмотрим все перечисленные оси. В данном примере осью является

    descendant
    , а имена элементов
    NAME
    ,
    MASS
    и
    DAY
    — это условия узлов.

    Шаги расположения XPath, часть 2: условия узлов

    При создании образцов в качестве условий узлов (node test) можно использовать имена узлов или символ подстановки * для выбора любого узла элемента. Например, выражение

    child::*/child::NAME
    выбирает все элементы
    <NAME>
    , являющиеся правнуками контекстного узла. В XPath кроме имен и символа подстановки можно также применять, как и в образцах выбора, следующие условия узлов:

    • условие узла

    comment()
    выбирает узлы комментария;

    • условие узла

    node()
    выбирает узел любого типа;

    • условие узла

    processing-instruction()
    выбирает узел инструкции обработки. В скобках можно указать название выбираемой инструкции обработки;

    • условие узла

    text()
    выбирает текстовый узел

    Например, в листинге 7.2 таблица стилей находит в документе все комментарии при помощи условия узла

    comment()
    и создает для каждого комментария новый,
    <!--Warning:comment found!-->
    (Внимание! Найден комментарий!).

    Листинг 7.2. Выбор комментариев

    <?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="/">

      <xsl:for-each select="descendant::comment()">

       <xsl:comment>Warning: comment found!</xsl:comment>

      </xsl:for-each>

     </xsl:template>

    </xsl:stylesheet>

    При применении этой таблицы стилей к

    planets.xml
    получается следующий документ:

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

    <!--Warning: comment found!-->

    <!--Warning: comment found!-->

    <!--Warning: comment found!-->

    Шаги расположения XPath, часть 3: предикаты

    Предикат в шаге расположения XPath сам содержит заключенное в скобки выражение XPath, которое вычисляется в истину или ложь. Когда результатом вычисления выражения является строка, XPath считает ее истиной, если строка не пуста. Когда результат — набор узлов, XPath считает его истиной, если он не пуст. Когда результат — число, то общий результат будет считаться истиной, если это число совпадает с контекстной позицией — например,

    PLANET[3]
    будет истиной тогда и только тогда, когда истиной будет
    PLANET[position()=3]
    .

    Предикаты содержат выражения XPath наподобие тех, которые встречались нам на протяжении этой главы: редко когда выражение возвращает набор узлов, главным образом возвращаются строки, числа или логические значения. Например, путь расположения

    preceding-sibling::MASS[position()*4]
    выбирает четыре предыдущих элемента-брата
    <MASS>
    для контекстного узла.

    Применение осей XPath

    К этому моменту мы рассмотрели три части шагов расположения — ось, условие узла и предикат. Вы должны быть знакомы с этими элементами по проделанной нами работе с образцами выбора, но обратите внимание на ось в предыдущем примере —

    preceding-sibling
    . До сих пор мы видели только оси, выбиравшие образцы XSLT — оси
    child
    и
    attribute
    ; теперь же мы рассмотрим новые оси, возможные в полных выражениях XPath, и начнем с оси
    ancestor
    .

    Применение оси ancestor

    Ось

    ancestor
    (предок) содержит всех предков контекстного узла, включая родителей, дедушек, прадедушек и т.д. Эта ось всегда содержит корневой узел — если только контекстным узлом не является сам корневой узел.

    Взгляните на листинг 7.3, в котором при помощи оси

    ancestor
    осуществляется поиск имен (хранимых в элементе
    <NAME>
    ) всех предков элементов
    <MASS>
    .

    Листинг 7.3. Применение оси ancestor

    <?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="MASS">

      <xsl:for-each select="ancestor::*">

       <xsl:value-of select="./NAME"/>

      </xsl:for-each>

     </xsl:template>


     <xsl:template match="PLANET">

      <xsl:apply-templates select="MASS"/>

     </xsl:template>

    </xsl:stylesheet>

    Вот результат применения этой таблицы стилей к

    planets.xml
    :

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

    Mercury

    Venus

    Earth

    Применение оси ancestor-or-self

    Ось

    ancestor-or-self
    содержит всех предков контекстного узла, а также сам контекстный узел. Это означает, помимо прочего, что такая ось всегда содержит корневой узел.

    В листинге 7.4 добавлены атрибуты

    AUTHOR
    со значением «Steve» в весь документ.

    Листинг 7.4. planets.xml с атрибутами AUTHOR

    <?xml version=1.0"?>

    <?xml-stylesheet type="text/xml" href="planets.xsl"?>

    <PLANETS AUTHOR="Steve" >

     <PLANET AUTHOR="Steve" >

      <NAME>Mercury</NAME>

      <MASS AUTHOR="Steve" 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 AUTHOR="Steve">

      <NAME>Venus</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><!--В перигелии-->

     </PLANET>

     <PLANET>

      <NAME>Earth</NAME>

      <MASS UNITS="(Earth = 1)">1</MASS>

      <DAY UNITS="days">1</DAY>

      <RADIUS UNITS="miles">2107</RADIUS>

      <DENSITY UNITS="(Earth = 1)">1</DENSITY>

      <DISTANCE UNITS="million miles">128.4</DISTANCE><!--B перигелии-->

     </PLANET>

    </PLANETS>

    Предположим теперь, что я хочу перечислить по имени всех предков элементов

    <MASS>
    , имеющих атрибут
    AUTHOR
    , а также текущий элемент
    <MASS>
    , если у него есть атрибут
    AUTHOR
    . Это можно сделать при помощи оси
    ancestor-or-self
    и функции
    local-name
    (листинг 7.5).

    Листинг 7.5. Применение оси ancestor-or-self

    <?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="MASS">

      <xsl:for-each select="ancestor-or-self::*[@AUTHOR]">

       <xsl:value-of select="local-name(.)"/>

       <xsl:text> </xsl:text>

      </xsl:for-each>

     </xsl:template>


     <xsl:template match="PLANET">

      <xsl:apply-templates select="MASS"/>

     </xsl:template>

    </xsl:stylesheet>

    Вот результат; показаны выбранные предки всех трех элементов

    <MASS>
    , включая сам элемент
    <MASS>
    , при условии, что у него имеется атрибут
    AUTHOR
    :

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

    PLANETS PLANET MASS

    PLANETS PLANET

    PLANETS

    Применение оси descendant

    Ось

    descendant
    (потомок) содержит всех потомков контекстного узла. Заметьте, что сюда не входят атрибуты или узлы пространств имен, поскольку они не считаются дочерними узлами.

    В следующем примере (листинг 7.6) демонстрируется работа с этой осью. На этот раз я хочу добавить примечание к элементу

    <PLANET>
    Меркурия:
    <INFO>Sorry, Mercury has blown up and is no longer available.</INFO>
    (Извините, но Меркурий взорвался и больше не доступен.). Чтобы найти Меркурий, мне достаточно только проверить, имеет ли какой-либо потомок элемента
    <PLANET>
    строковое значение «
    Mercury
    », что я сделаю при помощи выражения XPath внутри предиката выбора.

    Листинг 7.6. Применение оси descendant

    <?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="PLANET[descendant::*='Mercury']">

      <xsl:copy>

       <xsl:apply-templates select="@*|node()"/>

       <INFO>Sorry. Mercury has blown up and is no longer available.</INFO>

      </xsl:copy>

     </xsl:template>


     <xsl:template match="@*|node()">

      <xsl:copy>

       <xsl:apply-templates select="@*|node()"/>

      </xsl:copy>

     </xsl:template>

    </xsl:stylesheet>

    Вот результирующий документ, дополненный новым элементом

    <INFO>
    только для Меркурия:

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

    <?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><!--В перигелии-->

      <INFO>Sorry, Mercury has blown up and is no longer available.</INFO>

     </PLANET>

     <PLANET>

      <NAME>Venus</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>

     .

     .

     .

    </PLANETS>

    Применение оси descendant-or-self

    Ось

    descendant-or-self
    содержит всех потомков контекстного узла и сам контекстный узел. Заметьте, однако, что она не содержит атрибутов и узлов пространств имен.

    В следующем примере (листинг 7.7) демонстрируется работа с осью. В этом случае я создал упрощенную таблицу стилей (подробнее об упрощенных таблицах стилей см. главу 2), которая обрабатывает все элементы с использованием потомков, генерируя уже знакомую нам HTML-таблицу данных о планетах.

    Листинг 7.7. Применение оси descendant-or-self

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

     <HEAD>

      <TITLE>

       The Planets Table

      </TITLE>

     </HEAD>

     <BODY>

      <H1>

       The Planets Table

      </Н1>

      <TABLE BORDER="2">

       <TR>

        <TD>Name</TD>

        <TD>Mass</TD>

        <TD>Radius</TD>

        <TD>Day</TD>

       </TR>

       <xsl:for-each select="/descendant-or-self::node()/PLANET">

        <TR>

         <TD><xsl:value-of select="NAME"/></TD>

         <TD><xsl:value-of select="MASS"/></TD>

         <TD><xsl:value-of select="RADIUS"/></TD>

         <TD><xsl:value-of select="DAY"/></TD>

        </TR>

       </xsl:for-each>

      </TABLE>

     </BODY>

    </HTML>

    Вот и все. Я применил здесь упрощенную таблицу стилей, чтобы подчеркнуть, что при помощи таких осей потомков, как

    descendant
    или
    descendant-or-self
    , вы можете автоматически обрабатывать все выбираемые узлы, во многом аналогично тому, как это делают элементы
    <xsl:for-each>
    или
    <xsl:template>
    .

    Применение оси following

    Ось following (следующий) содержит все узлы, расположенные после контекстного узла в соответствии с установленным в документе порядком (другими словами, в порядке, в котором они появляются в документе, начиная с его начала), исключая всех потомков контекстного узла, а также исключая узлы атрибутов и пространств имен.

    В этом примере (листинг 7.8) я выбираю каждый элемент <PLANET> и копирую все последующие элементы в результирующий документ.

    Листинг 7.8. Применение оси following

    <?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="PLANET">

      <xsl:for-each select="following::*">

       <xsl:copy-of select="."/>

      </xsl:for-each>

     </xsl:template>

    </xsl:stylesheet>

    Далее показан результат. Обратите внимание на то, что, когда этот шаблон выбирает элемент

    <PLANET>
    Меркурия, он копирует все последующие элементы — то есть Венеру, затем всех потомков Венеры, далее Землю и затем всех потомков Земли. После этого он выбирает элемент
    <PLANET>
    Венеры и копирует все следующие элементы, то есть Землю и всех потомков Земли:

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

    <PLANET>

     <NAME>Venus</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>

    <NAME>Venus</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>

    <PLANET>

     <NAME>Earth</NAME>

     <MASS UNITS="(Earth = 1)">1</MASS>

     <DAY UNITS="days">1</DAY>

     <RADIUS UNITS="miles">2107</RADIUS>

     <DENSITY UNITS="(Earth = 1)">1</DENSITY>

     <DISTANCE UNITS="million miles">128.4</DISTANCE><!--B перигелии-->

    </PLANET>

    <NAME>Earth</NAME>

    <MASS UNITS="(Earth = 1)">1</MASS>

    <DAY UNITS="days">1</DAY>

    <RADIUS UNITS="miles">2107</RADIUS>

    <DENSITY UNITS="(Earth = 1)">1</DENSITY>

    <DISTANCE UNITS="million miles">128.4</DISTANCE>

    <PLANET>

     <NAME>Earth</NAME>

     <MASS UNITS="(Earth = 1)">1</MASS>

     <DAY UNITS="days">1</DAY>

     <RADIUS UNITS="miles">2107</RADIUS>

     <DENSITY UNITS="(Earth = 1)">1</DENSITY>

     <DISTANCE UNITS="million miles">128.4</DISTANCE><!--B перигелии-->

    </PLANET>

    <NAME>Earth</NAME>

    <MASS UNITS="(Earth = 1)">1</MASS>

    <DAY UNITS="days">1</DAY>

    <RADIUS UNITS="miles">2107</RADIUS>

    <DENSITY UNITS="(Earth = 1)">1</DENSITY>

    <DISTANCE UNITS="million miles">128.4</DISTANCE>

    С другой стороны, при использовании оси

    following-sibling
    в результирующий документ будут скопированы только следующие братья, то есть только элементы
    <PLANET>
    , как мы увидим в следующем разделе.

    Применение оси following-sibling

    Ось

    following-sibling
    содержит всех последующих братьев контекстного узла.

    Например, я могу выбрать каждый элемент

    <PLANET>
    и скопировать в результирующий документ все узлы в оси
    following-sibling
    следующим образом (листинг 7.9).

    Листинг 7.9. Применение оси following-sibling

    <?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="PLANET">

      <xsl:for-each select="following-sibling::*">

       <xsl:copy-of select="."/>

      <xsl:for-each>

     </xsl:template>

    </xsl:stylesheet>

    При этом сначала копируются два узла-брата, следующие за Меркурием (Венера и Земля), затем копируется следующий узел-брат Венеры, Земля. У самой Земли нет следующих за ней братьев, поэтому результат выглядит так:

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

    <PLANET>

     <NAME>Venus</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>

    <PLANET>

     <NAME>Earth</NAME>

     <MASS UNITS="(Earth = 1)">1</MASS>

     <DAY UNITS="days">1</DAY>

     <RADIUS UNITS="miles">2107</RADIUS>

     <DENSITY UNITS="(Earth = 1)">1</DENSITY>

     <DISTANCE UNITS="million miles">128.4</DISTANCE><!--B перигелии-->

    </PLANET>

    <PLANET>

     <NAME>Earth</NAME>

     <MASS UNITS="(Earth = 1)">1</MASS>

     <DAY UNITS="days">1</DAY>

     <RADIUS UNITS="miles">2107</RADIUS>

     <DENSITY UNITS="(Earth = 1)">1</DENSITY>

     <DISTANCE UNITS="million miles">128.4</DISTANCE><!--B перигелии-->

    </PLANET>

    Применение оси namespace

    Ось

    namespace
    содержит узлы пространств имен контекстного узла. Заметьте, что эта ось пуста, если контекстным узлом не является элемент. У элемента присутствует узел пространства имен для:

    • каждого атрибута элемента, чье имя начинается с «xmlns:»;

    • каждого атрибута элемента-предка, чье имя начинается с «xmlns:» (конечно, если сам элемент или ближайший предок не объявит пространство имен заново);

    • атрибута

    xmlns
    , если элемент или предок имеет атрибут
    xmlns
    .

    В следующем примере (листинг 7.10) я хочу отобразить пространство имен элемента

    <PLANET>
    в результирующем документе, и в исходном документе я присвоил пространству имен значение «http://www.starpowder.com».

    Листинг 7.10. planets.xml с объявлением пространства имен

    <?xml version="1.0"?>

    <?xml-stylesheet type="text/xml" href="planets.xsl"?>

    <PLANETS xmlns="http://www.starpowder.com">

     <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><!--В перигелии-->

     </PLANET>

     .

     .

     .

    Вот таблица стилей (листинг 7.11), в которой я проверяю пространства имен, используемые в элементе

    <PLANETS>
    .

    Листинг 7.11. Применение оси namespace в planets.xml

    <?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">

      <xsl:value-of select="namespace::*"/>

     </xsl:template>

    </xsl:stylesheet>

    А вот результирующий документ (заметьте, что вид документа может меняться в зависимости от процессора XSLT):

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

    http://www.starpowder.com

    Применение оси parent

    Ось parent (родитель) содержит родителя (и только родителя) контекстного узла, если таковой имеется.

    Предположим, что я хочу изменить содержимое элемента Земли

    <MASS>
    на «The mass of Earth is set to 1.>> (Масса Земли принимается за 1). В следующем шаблоне (листинг 7.12) для этого проверяется, содержит ли родитель
    <PLANET>
    элемента
    <MASS>
    элемент
    <NAME>
    со строковым значением «Earth».

    Листинг 7.12. Применение оси parent

    <?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="@*|node()">

      <xsl:copy>

       <xsl:apply-templates select="@*|node()"/>

      </xsl:copy>

     </xsl:template>


     <xsl:template match="MASS[parent::node()/NAME='Earth']">

      <MASS>The mass of Earth is set to 1.</MASS>

     </xsl:template>

    </xsl:stylesheet>

    И вот результат:

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

    <?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>Venus</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>

     <PLANET>

      <NAME>Earth</NAME>

      <MASS>The mass of Earth is set to 1.</MASS>

      <DAY UNITS="days">1</DAY>

      <RADIUS UNITS="miles">2107</RADIUS>

      <DENSITY UNITS="(Earth = 1)">1</DENSITY>

      <DISTANCE UNITS="million miles">128.4</DISTANCE><!--B перигелии-->

     </PLANET>

    </PLANETS>

    Применение оси preceding

    Ось

    preceding
    содержит все узлы, расположенные перед контекстным узлом в соответствии с установленным в документе порядком, исключая всех предков контекстного узла, а также исключая узлы атрибутов и узлы пространств имен.

    Пусть, например, мне нужно задать для содержимого элемента

    <DISTANCE>
    текст «This planet is farther from the Sun than Mercury.» (Эта планета расположена дальше от Солнца, чем Меркурий.), если рассматриваемая планета действительно дальше от Солнца, чем Меркурий. Один из способов сделать это — проверить, расположен ли Меркурий перед рассматриваемой планетой в соответствии с установленным в документе порядком, при помощи оси
    preceding
    (листинг 7.13).

    Листинг 7.13. Применение оси preceding

    <?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="DISTANCE[preceding::*/NAME='Mercury']">

      <DISTANCE>This planet is farther from the Sun than Mercury.</DISTANCE>

     </xsl:template>

     <xsl:template match="@*|node()">

      <xsl:copy>

       <xsl:apply-templates select="@*|node()"/>

      </xsl:copy>

     </xsl:template>

    </xsl:stylesheet>

    Если текущая планета расположена после Меркурия, я могу вставить сообщение в ее элемент

    <DISTANCE>
    . Результат следующий:

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

    <?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> <!--В перигелии-->

     </PLANET>

     <PLANET>

      <NAME>Venus</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>This planet is farther from the Sun than Mercury.</DISTANCE> <!--В перигелии-->

     </PLANET>

     <PLANET>

      <NAME>Earth</NAME>

      <MASS UNITS="(Earth = 1)">1</MASS>

      <DAY UNITS="days">1</DAY>

      <RADIUS UNITS="miles">2107</RADIUS>

      <DENSITY UNITS="(Earth = 1)">1</DENSITY>

      <DISTANCE>This planet is farther from the Sun than Mercury.</DISTANCE> <!--В перигелии-->

     </PLANET>

    </PLANETS>

    Применение оси preceding-sibling

    Ось

    preceding-sibling
    содержит всех предшествующих братьев контекстного узла. Заметьте, что если контекстным узлом является узел атрибута или узел пространства имен, ось
    preceding-sibling
    будет пуста.

    Что, если, например, вам нужно создать шаблон, который будет выбирать только элементы

    <DISTANCE>
    в элементе
    <PLANET>
    Меркурия? Для этого можно проверить, существуют ли братья, предшествующие элементу
    <DISTANCE>
    , которые являются элементами
    <NAME>
    со строковым значением «
    Mercury
    ». Если применить ось
    preceding-sibling
    (листинг 7.14), поиск будет ограничен текущим элементом
    <PLANET>
    , что означает, что Меркурий не будет выбран, если вы только не находитесь в нужном элементе
    <PLANET>
    .

    Листинг 7.14. Применение оси preceding-sibling

    <?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="DISTANCE[preceding-sibling::*='Mercury']">

      <DISTANCE>This is the planet Mercury, closest to the Sun.</DISTANCE>

     </xsl:template>


     <xsl:template match="@*|node()">

      <xsl:copy>

       <xsl:apply-templates select="@*|node()"/>

      </xsl:copy>

     </xsl:template>

    </xsl:stylesheet>

    А вот результат:

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

    <?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>This is the planet Mercury, closest to the Sun.</DISTANCE> <!--В перигелии-->

     </PLANET>

     <PLANET>

      <NAME>Venus</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>

     <PLANET>

      <NAME>Earth</NAME>

      <MASS UNITS="(Earth = 1)">1</MASS>

      <DAY UNITS="days">1</DAY>

      <RADIUS UNITS="miles">2107</RADIUS>

      <DENSITY UNITS="(Earth = 1)">1</DENSITY>

      <DISTANCE UNITS="million miles">128.4</DISTANCE><!--B перигелии-->

     </PLANET>

    </PLANETS>

    Применение оси self

    Ось

    self
    содержит только контекстный узел. В соответствии с одним из сокращений XPath, как мы увидим дальше, вместо «
    self::node()
    » можно использовать «.».

    Эту ось полезно иметь в виду, поскольку, как вы помните из главы 4, если не задать ось, осью по умолчанию будет

    child::
    , а в некоторых случаях вам может понадобиться обратиться к действующему узлу. Например,
    [self::PLANET]
    примет значение истины только если контекстным узлом будет элемент
    <PLANET>
    .

    В следующем примере я объединяю шаблоны для элементов

    <NAME>
    и
    <MASS>
    в один шаблон. Поскольку у этих элементов разный формат, я должен обращаться с ними по-разному внутри одного и того же шаблона (что можно сделать проверкой значений оси
    self::NAME
    , которая возвращает непустой набор узлов, если контекстным, узлом является элемент
    <NAME>
    , и
    self::MASS
    , возвращающей непустой набор узлов, если контекстным узлом является элемент
    <MASS>
    ):

    <xsl:template match="PLANET">

     <TR>

      <TD><xsl:apply-templates select="NAME"/></TD>

      <TD><xsl:apply-templates select="MASS"/></TD>

      <TD><xsl:apply-templates select="RADIUS"/></TD>

      <TD><xsl:apply-templates select="DAY"/></TD>

     </TR>

    </xsl:template>


    <xsl:template match="NAME | MASS">

     <xsl:if test="self::NAME">

      <xsl:value-of select="."/>

     </xsl:if>

     <xsl:if test="self::MASS">

      <xsl:value-of select="."/>

      <xsl:text> </xsl:text>

      <xsl:value-of select="@UNITS"/>

     </xsl:if>

    </xsl:template>

    .

    .

    .

    На этом мы завершаем рассмотрение новых осей XPath. Давайте перейдем к примерам.

    Примеры путей расположения

    Мы изучили достаточно теории путей расположения. Но, понятно, лучше всего осваивать этот материал на примерах, поэтому я привожу следующий список примеров путей расположения (сокращенные варианты рассматриваются после этого списка):

    • 

    child::PLANЕТ
    . Возвращает дочерние элементы
    <PLANЕТ>
    контекстного узла;

    • 

    child::text()
    . Возвращает все дочерние текстовые узлы контекстного узла;

    • 

    child::node()
    . Возвращает всех детей контекстного узла;

    • 

    attribute::UNIT
    . Возвращает атрибут
    UNIT
    контекстного узла;

    • 

    descendant::PLANET
    . Возвращает все элементы-потомки
    <PLANET>
    контекстного узла;

    • 

    ancestor::PLANET
    . Возвращает всех предков
    <PLANET>
    контекстного узла;

    • 

    ancestor-or-self::PLANET
    . Возвращает предков
    <PLANET>
    контекстного узла. Если контекстным узлом тоже является
    <PLANET>
    , возвращает также контекстный узел;

    • 

    descendant-or-self::PLANET
    . Возвращает элементы-потомки
    <PLANET>
    контекстного узла. Если контекстным узлом тоже является
    <PLANET>
    , возвращает также контекстный узел;

    • 

    self::PLANET
    . Возвращает контекстный узел, если им является элемент
    <PLANET>
    ;

    • 

    child::PLANET/descendant::NAME
    . Возвращает элементы-потомки
    <NAME>
    дочерних элементов
    <PLANET>
    контекстного узла;

    • 

    child::*/child::PLANET
    . Возвращает всех внуков
    <PLANET>
    контекстного узла;

    • 

    /
    . Возвращает корневой узел;

    • 

    /descendant::PLANET
    . Возвращает все элементы
    <PLANET>
    в документе;

    • 

    /descendant::PLANET/child::NAME
    . Возвращает все элементы
    <NAME>
    с родителем
    <PLANET>
    в документе;

    • 

    child::PLANET[position()=3]
    . Возвращает третьего ребенка
    <PLANET>
    контекстного узла;

    • 

    child::PLANET[position()=last()]
    . Возвращает последнего ребенка
    <PLANET>
    контекстного узла;

    • 

    /descendant::PLANET[position() = 3]
    . Возвращает третий элемент
    <PLANET>
    в документе;

    • 

    child::PLANETS/child::PLANET[position()=4]/child::NAME[position()=3]
    . Возвращает третий элемент
    <NAME>
    четвертого элемента
    <PLANET>
    элемента
    <PLANETS>
    ;

    • 

    child::PLANET[position()>3]
    . Возвращает всех детей
    <PLANET>
    контекстного узла после первых трех;

    • 

    preceding-sibling::NAME[position()=2]
    . Возвращает второй предыдущий элемент-брат
    <NAME>
    контекстного узла;

    • 

    child::*[self::NAME or self::MASS]
    . Возвращает детей
    <NAME>
    и
    <MASS>
    контекстного узла.

    • 

    child::*[self::NAME or self::MASS][position()=last()]
    . Возвращает последнего ребенка
    <NAME>
    или
    <MASS>
    контекстного узла.

    Как видите, синтаксис некоторых выражений достаточно запутан, и набирать их также довольно долго. Но, как и для образцов, существует сокращенная форма синтаксиса XPath.

    Сокращенный синтаксис XPath

    Сокращения синтаксиса XPath могут быть весьма удобными. Ниже приведены правила:

    • 

    self::node()
    может быть сокращено как
    .
    ;

    • 

    parent::node()
    может быть сокращено как
    ..
    ;

    • 

    child::childname
    может быть сокращено как
    childname
    ;

    • 

    attribute::childname
    может быть сокращено как
    @childname
    ;

    • 

    /descendant-or-self::node()/
    может быть сокращено как
    //
    .

    Например, путь расположения

    .//PLANET
    — сокращение для
    self::node()/descendant-or-self::node()/child::PLANET
    . Можно также сократить выражение предиката
    [position()=3]
    как
    [3]
    ,
    [position()=last()]
    как
    [last()]
    и т.д. Работать с путями расположения XPath при помощи сокращенного синтаксиса значительно проще. В следующем списке перечислен ряд примеров путей расположения с использованием сокращенного синтаксиса:

    • 

    PLANET
    возвращает дочерние элементы
    <PLANET>
    контекстного узла;

    • 

    *
    возвращает все дочерние элементы контекстного узла;

    • 

    text()
    возвращает все дочерние текстовые узлы контекстного узла;

    • 

    @UNITS
    возвращает атрибут
    UNITS
    контекстного узла;

    • 

    @*
    возвращает все атрибуты контекстного узла;

    • 

    PLANET[3]
    возвращает третьего ребенка
    <PLANET>
    контекстного узла;

    • 

    PLANET[last()]
    возвращает последнего ребенка
    <PLANET>
    контекстного узла;

    • 

    */PLANET
    возвращает всех внуков
    <PLANET>
    контекстного узла;

    • 

    /PLANETS/PLANET[3]/NAME[2]
    возвращает второй элемент
    <NAME>
    третьего элемента
    <PLANET>
    элемента
    <PLANETS>
    ;

    • 

    //PLANET
    возвращает всех потомков
    <PLANET>
    корня документа;

    • 

    PLANETS//PLANET
    возвращает элементы-потомки
    <PLANET>
    дочерних элементов
    <PLANETS>
    контекстного узла;

    • 

    //PLANET/NAME
    возвращает все элементы
    <NAME>
    , у которых есть родитель
    <PLANET>
    ;

    • 

    .
    возвращает сам контекстный узел;

    • 

    .//PLANET
    возвращает элементы-потомки
    <PLANET>
    контекстного узла;

    • 

    ..
    возвращает родителя контекстного узла;

    • 

    ../@UNITS
    возвращает атрибут
    UNITS
    родителя контекстного узла;

    • 

    .//..
    возвращает всех родителей потомка контекстного узла и родителя контекстного узла;

    • 

    PLANET[NAME]
    возвращает детей
    <PLANET>
    контекстного узла, у которых есть дети
    <NAME>
    ;

    • 

    PLANET[NAME="Venus"]
    возвращает детей
    <PLANET>
    контекстного узла, у которых есть дети
    <NAME>
    с текстом, равным «Venus»;

    • 

    PLANET[@UNITS="days"]
    возвращает всех детей
    <PLANET>
    контекстного узла, у которых есть атрибут
    UNITS
    со значением «
    days
    »;

    • 

    PLANET[6][@UNITS="days"]
    возвращает шестого ребенка
    <PLANET>
    контекстного узла, только если у этого ребенка есть атрибут
    UNITS
    со значением «days». Можно также написать
    PLANET[@UNITS="days"][6]
    ;

    • 

    PLANET[@COLOR and @UNITS]
    возвращает всех детей
    <PLANET>
    контекстного узла, у которых есть атрибут
    COLOR
    и атрибут
    UNITS
    ;

    • "

    //PLANET[not(.=preceding::PLANET)]
    " выбирает все элементы
    <PLANET>
    , значение которых отлично от значения любого предшествующего элемента
    <PLANET>
    ;

    • 

    *[1][self::NAME]
    выбирает любой элемент
    <NAME>
    , который является первым ребенком своего родителя;

    • 

    *[position() &lt; 5][@UNITS]
    выбирает первых пятерых детей контекстного узла, у которых есть атрибут
    UNITS
    .

    Проверка выражений XPath

    В пакет Xalan входит удобная программа-пример, ApplyXPath.java, позволяющая применить выражение XPath к документу и посмотреть на результат, что очень помогает при тестировании. Для запуска этого примера вам нужно будет скомпилировать

    ApplyXPath.java
    в
    ApplyXPath.class
    при помощи утилиты java.exe, входящей в поставку Java.

    В качестве примера я применю выражение XPath «

    PLANET/NAME
    » к
    planets.xml
    при помощи
    ApplyXPath.class
    . Ниже показан результат, отображающий все элементы
    <NAME>
    , дочерние по отношению к элементам
    <PLANET>
    (теги
    <output>
    добавлены программой ApplyXPath):

    %java ApplyXPath planets.xml PLANET/NAME

    <output>

     <NAME>Mercury</NAME><NAME>Venus</NAME><NAME>Earth</NAME>

    </output>

    XPath 2.0

    XPath находится в стадии обновления, и в него включаются средства поддержки XSLT 2.0 (см. www.w3.org/TR/xpath20req). Задачи XPath 2.0 следующие:

    • упрощение операций с содержимым типов, поддерживаемых схемой XML;

    • упрощение операций со строковым содержимым;

    • поддержка соответствующих стандартов XML;

    • улучшение удобства использования;

    • улучшение функциональной совместимости;

    • улучшение поддержки международных языковых средств;

    • сохранение обратной совместимости;

    • повышенная эффективность процессора.

    Следующий список дает обзор требований XPath. Главные пункты — поддержка схемы XML и регулярных выражений, что дает средства работы со строками и поиска в строках. (Дополнительную информацию о регулярных выражениях можно почерпнуть по адресу http://www.perldoc.com/perl5.6/pod/perlre.html.) В соответствии с W3C, XPath 2.0:

    • должен поддерживать архитектуру XML W3C, хорошо взаимодействуя с другими стандартами в семействе XML;

    • должен выражать свою модель данных в терминах информационного множества (infoset) XML;

    • должен предоставлять общий ключевой синтаксис для XSLT 2.0 и XML Query language 1.0;

    • должен поддерживать явное сравнение «

    for any
    » или «
    for all
    » и синтаксис равенства;

    • должен расширять множество функций агрегации (например, пользователи XSLT часто требовали добавить функции

    min()
    и
    max()
    );

    • должен сохранять обратную совместимость с XPath 1.0;

    • должен предоставлять функции пересечения и разности то есть — XPath 1.0 поддерживает объединение двух наборов узлов, и к этому должны быть добавлены функции пересечения и разности;

    • должен поддерживать операцию унарного плюса (поскольку в схеме XML у десятичных чисел может присутствовать лидирующий плюс);

    • должен улучшать удобство использования;

    • должен снизить ограничения на шаги расположения;

    • должен реализовывать условную операцию, оперирующую тремя выражениями — выражением 1 (логическая операция), выражением 2 и выражением 3. Если выражение 1 принимает значение «истина», должно вычисляться выражение 2, а если выражение 1 принимает значение «ложь», должно вычисляться выражение 3;

    • должен определять последовательный синтаксис для подвыражений, обрабатывающих коллекции элементов;

    • должен поддерживать дополнительные строковые функции. Например, W3C рассматривает вопрос добавления средств для замены в строках, заполнения символами и преобразований регистра;

    • должен поддерживать функции агрегации при применении к коллекциям. Например, некоторым пользователям XPath 1.0 требовалось применить такую функцию агрегации, как

    sum
    , к значениям выражений, примененных к наборам узлов;

    • должен поддерживать регулярные выражения для поиска в строках с использованием нотации регулярных выражений, установленной в схеме XML;

    • должен поддерживать элементарные типы данных схемы XML. То есть в дополнение к типам, поддерживаемым моделью данных XPath 1.0, — строке, числу, логическому значению и набору узлов — модель данных XPath 2.0 должна поддерживать элементарные типы данных схемы XML;

    • должен поддерживать представления чисел с плавающей точкой одинарной и двойной точности, поддерживаемые схемой XML, которая использует научную нотацию;

    • должен определять подходящий набор функций для работы пользователя с элементарными типами данных схемы XML;

    • должен добавлять в XPath тип данных «список» (поскольку схема XML позволяет определять простые типы, унаследованные от списка);

    • должен поддерживать доступ к значениям простых типов элементов и атрибутов. Поскольку схемы XML представляют много новых типов, XPath 2.0 должен поддерживать доступ к собственному, простого типа, значению элемента или атрибута;

    • должен определять поведение операторов для нулевых аргументов; 

    • должен иметь средства для выбора элементов или атрибутов на основе явного типа схемы XML;

    • должен иметь средства для выбора элементов или атрибутов на основе иерархии типов схемы XML;

    • должен иметь средства для выбора элементов на основе групп подстановки схемы XML;

    • должен поддерживать средства поиска, основанные на уникальных ограничениях и ключах схемы.

    Хотя мы подошли к концу главы, о XPath сказано еще не все. Тема будет продолжена в следующей главе, в которой мы более внимательно рассмотрим доступные в XPath функции и функции, уже встроенные в XSLT. 







     


    Главная | В избранное | Наш E-MAIL | Добавить материал | Нашёл ошибку | Наверх