XPath за 10 минут
XPath описан в стандарте. Согласно написанному там "XPath is a language for addressing parts of an XML document ... ". По-русски можно сказать, что XPath нужен для разбора (parsing) XML документов. В приведенных ниже примерах рассматриваются наиболее часто употребимые (по мнению автора) конструкции языка.
Если путь начинается с символа /, то он представляет абсолютный путь к заданному элементу.
| /AAA | /AAA/DDD/EEE |
<AAA> <BBB/> <CCC/> <BBB/> <DDD> <EEE/> </DDD> <CCC/> </AAA> |
<AAA>
<BBB/>
<CCC/>
<BBB/>
<DDD>
<EEE/>
</DDD>
<CCC/>
</AAA>
|
Если путь начинается с //, то будут выбраны все элементы, соответствующие указанному шаблону.
| //BBB | //DDD/BBB |
<AAA> <BBB/> <CCC/> <BBB/> <DDD> <BBB/> </DDD> <CCC> <DDD> <BBB/> <BBB/> </DDD> </CCC> </AAA> |
<AAA> <BBB/> <CCC/> <BBB/> <DDD> <BBB/> </DDD> <CCC> <DDD> <BBB/> <BBB/> </DDD> </CCC> </AAA> |
Символ * подразумевает любой узел в пути.
| /AAA/CCC/DDD/* | /*/*/*/BBB | //* |
<AAA> <XXX> <DDD> <BBB/> <BBB/> <EEE/> <FFF/> </DDD> </XXX> <CCC> <DDD> <BBB/> <BBB/> <EEE/> <FFF/> </DDD> </CCC> <CCC> <BBB> <BBB> <BBB/> </BBB> </BBB> </CCC> </AAA> |
<AAA> <XXX> <DDD> <BBB/> <BBB/> <EEE/> <FFF/> </DDD> </XXX> <CCC> <DDD> <BBB/> <BBB/> <EEE/> <FFF/> </DDD> </CCC> <CCC> <BBB> <BBB> <BBB/> </BBB> </BBB> </CCC> </AAA> |
<AAA> <XXX> <DDD> <BBB/> <BBB/> <EEE/> <FFF/> </DDD> </XXX> <CCC> <DDD> <BBB/> <BBB/> <EEE/> <FFF/> </DDD> </CCC> <CCC> <BBB> <BBB> <BBB/> </BBB> </BBB> </CCC> </AAA> |
Выражение в квадратных скобках позволяет задавать порядковые критерии для элемента. Так число в квадратных скобках обозначает позицию элемента в выбранном множестве. Функция last() позволяет указать последний элемент в выборке.
| /AAA/BBB[2] | /AAA/BBB[last()] |
<AAA>
<BBB/>
<BBB/>
<BBB/>
<BBB/>
</AAA>
|
<AAA>
<BBB/>
<BBB/>
<BBB/>
<BBB/>
</AAA>
|
Атрибуты определяются префиксом @
| //@id | //BBB[@id] | //BBB[@name] |
<AAA> <BBB id="b1"/> <BBB id="b2"/> <BBB name="bbb"/> <BBB/> <CCC id="c1"/> <CCC/> </AAA> |
<AAA> <BBB id="b1"/> <BBB id="b2"/> <BBB name="bbb"/> <BBB/> <CCC id="c1"/> <CCC/> </AAA> |
<AAA>
<BBB id="b1"/>
<BBB id="b2"/>
<BBB name="bbb"/>
<BBB/>
<CCC id="c1"/>
<CCC/>
</AAA>
|
Значения атрибутов могут служить критерием при выборке. Функция normalize-space() удаляет пробелы в начале и конце параметра, а все последовательности пробельных символов заменяет одиночным пробелом.
| //BBB[@id='b1'] | //BBB[@name='bbb'] | //BBB[normalize-space(@name)='bbb'] |
<AAA>
<BBB id="b1"/>
<BBB name=" bbb "/>
<BBB name="bbb"/>
</AAA>
|
<AAA>
<BBB id="b1"/>
<BBB name=" bbb "/>
<BBB name="bbb"/>
</AAA>
|
<AAA> <BBB id="b1"/> <BBB name=" bbb "/> <BBB name="bbb"/> </AAA> |
Функция count() возвращает число элементов в указанном множестве.
| //*[count(*)=3] выбрать все, имеющие три дочерних элемента |
//*[count(BBB)=2] выбрать все, имеющие два дочерних элемента BBB |
<AAA> <CCC> <BBB/> <BBB/> <BBB/> </CCC> <DDD> <BBB/> <BBB/> </DDD> <EEE> <CCC/> <DDD/> </EEE> </AAA> |
<AAA> <CCC> <BBB/> <BBB/> <BBB/> </CCC> <DDD> <BBB/> <BBB/> </DDD> <EEE> <CCC/> <DDD/> </EEE> </AAA> |
Функция name() возвращает имя элемента. Функция starts-with() возвращает истину, если строка первого аргумента начинается строкой второго аргумента. Функция contains() возвращает истину, если строка из первого аргумента содержит строку из второго.
| //*[name()='BBB']
выбрать все с именем BBB, эквивалентно пути //BBB |
//*[starts-with(name(),'B')]
выбрать все, имя которых начинается с B |
//*[contains(name(),'C')]
выбрать все, имя которых содержит C |
<AAA> <BCC> <BBB/> <BBB/> <BBB/> </BCC> <DDB> <BBB/> <BBB/> </DDB> <BEC> <CCC/> <DBD/> </BEC> </AAA> |
<AAA> <BCC> <BBB/> <BBB/> <BBB/> </BCC> <DDB> <BBB/> <BBB/> </DDB> <BEC> <CCC/> <DBD/> </BEC> </AAA> |
<AAA> <BCC> <BBB/> <BBB/> <BBB/> </BCC> <DDB> <BBB/> <BBB/> </DDB> <BEC> <CCC/> <DBD/> </BEC> </AAA> |
Функция string-length() возвращает число символов в строке.
| //*[string-length(name()) = 3]
выбрать все, имя которых состоит из трех символов |
//*[string-length(name()) < 3]
выбрать все, с именем меньше трех символов |
//*[string-length(name()) > 3]
выбрать все, с именем больше трех символов |
<AAA> <Q/> <SSSS/> <BB/> <CCC/> <DDDDDDDD/> <EEEE/> </AAA> |
<AAA> <Q/> <SSSS/> <BB/> <CCC/> <DDDDDDDD/> <EEEE/> </AAA> |
<AAA> <Q/> <SSSS/> <BB/> <CCC/> <DDDDDDDD/> <EEEE/> </AAA> |
Несколько путей можно объединить с помощью разделителя |
| /AAA/EEE | //BBB | /AAA/EEE | //DDD/CCC | /AAA | //BBB |
<AAA> <BBB/> <CCC/> <DDD> <CCC/> </DDD> <EEE/> </AAA> |
<AAA> <BBB/> <CCC/> <DDD> <CCC/> </DDD> <EEE/> </AAA> |
Ось descendant содержит всех потомков контекстного узла.
| /AAA/BBB/descendant::*
выбрать всех потомков узла AAA/BBB |
//CCC/descendant::*
выбрать всех потомков узла CCC |
//CCC/descendant::DDD
выбрать узел DDD, если он потомок CCC |
<AAA> <BBB> <DDD> <CCC> <DDD/> <EEE/> </CCC> </DDD> </BBB> <CCC> <GGG> <EEE> <DDD> <FFF/> </DDD> </EEE> </GGG> </CCC> </AAA> |
<AAA> <BBB> <DDD> <CCC> <DDD/> <EEE/> </CCC> </DDD> </BBB> <CCC> <GGG> <EEE> <DDD> <FFF/> </DDD> </EEE> </GGG> </CCC> </AAA> |
<AAA> <BBB> <DDD> <CCC> <DDD/> <EEE/> </CCC> </DDD> </BBB> <CCC> <GGG> <EEE> <DDD> <FFF/> </DDD> </EEE> </GGG> </CCC> </AAA> |
Ось parent содержит родителя контекстного узла, если он существует.
| //DDD/parent::*
выбрать родителей DDD |
//DDD/parent::BBB
выбрать BBB, если он родитель DDD |
<AAA> <BBB> <DDD> <CCC> <EEE/> <FFF/> </CCC> </DDD> </BBB> <CCC> <GGG> <EEE> <DDD> <FFF/> </DDD> </EEE> </GGG> </CCC> </AAA> |
<AAA> <BBB> <DDD> <CCC> <EEE/> <FFF/> </CCC> </DDD> </BBB> <CCC> <GGG> <EEE> <DDD> <FFF/> </DDD> </EEE> </GGG> </CCC> </AAA> |
Ось ancestor содержит всех предков контекстного узла. Таким образом, эта ось всегда содержит корневой узел.
| /AAA/BBB/DDD/CCC/EEE/ancestor::* | //FFF/ancestor::* |
<AAA> <BBB> <DDD> <CCC> <DDD/> <EEE/> </CCC> </DDD> </BBB> <CCC> <DDD> <EEE> <DDD> <FFF/> </DDD> </EEE> </DDD> </CCC> </AAA> |
<AAA> <BBB> <DDD> <CCC> <DDD/> <EEE/> </CCC> </DDD> </BBB> <CCC> <DDD> <EEE> <DDD> <FFF/> </DDD> </EEE> </DDD> </CCC> </AAA> |
Ось following-sibling содержит все последующих братьев контекстного узла. Братьями называются те узлы, что имеют одного родителя с контекстным.
| /AAA/BBB/following-sibling::* | //CCC/following-sibling::* |
<AAA> <BBB> <CCC/> <DDD/> </BBB> <XXX> <DDD> <EEE/> <DDD/> <CCC/> <FFF/> <FFF> <GGG/> </FFF> </DDD> </XXX> <CCC> <DDD/> </CCC> </AAA> |
<AAA> <BBB> <CCC/> <DDD/> </BBB> <XXX> <DDD> <EEE/> <DDD/> <CCC/> <FFF/> <FFF> <GGG/> </FFF> </DDD> </XXX> <CCC> <DDD/> </CCC> </AAA> |
Ось preceding-sibling содержит всех предыдущих братьев контекстного узла.
| /AAA/XXX/preceding-sibling::* | //CCC/preceding-sibling::* |
<AAA> <BBB> <CCC/> <DDD/> </BBB> <XXX> <DDD> <EEE/> <DDD/> <CCC/> <FFF/> <FFF> <GGG/> </FFF> </DDD> </XXX> <CCC> <DDD/> </CCC> </AAA> |
<AAA> <BBB> <CCC/> <DDD/> </BBB> <XXX> <DDD> <EEE/> <DDD/> <CCC/> <FFF/> <FFF> <GGG/> </FFF> </DDD> </XXX> <CCC> <DDD/> </CCC> </AAA> |
Ось following содержит все узлы, идущие после контекстного, в том же порядке, что и в самом документе, за исключением всех предков, узлов атрибутов и пространств имен.
| /AAA/XXX/DDD/FFF/following::* | //ZZZ/following::* |
<AAA> <BBB> <CCC/> <ZZZ> <DDD/> <DDD> <EEE/> </DDD> </ZZZ> <FFF> <GGG/> </FFF> </BBB> <XXX> <DDD> <EEE/> <DDD/> <CCC/> <FFF/> <HHH> <GGG/> </HHH> </DDD> </XXX> <CCC> <DDD/> </CCC> </AAA> |
<AAA> <BBB> <CCC/> <ZZZ> <DDD/> <DDD> <EEE/> </DDD> </ZZZ> <FFF> <GGG/> </FFF> </BBB> <XXX> <DDD> <EEE/> <DDD/> <CCC/> <FFF/> <HHH> <GGG/> </HHH> </DDD> </XXX> <CCC> <DDD/> </CCC> </AAA> |
Ось preceding содержит все узлы, идущие перед контекстным узлом, в том же порядке, что и в самом документе, исключая любых предков, узлов атрибутов и пространств имен.
| /AAA/XXX/preceding::* | //GGG/preceding::* |
<AAA> <BBB> <CCC/> <ZZZ> <DDD/> </ZZZ> </BBB> <XXX> <DDD> <EEE/> <DDD/> <CCC/> <FFF/> <FFF> <GGG/> </FFF> </DDD> </XXX> <CCC> <DDD/> </CCC> </AAA> |
<AAA> <BBB> <CCC/> <ZZZ> <DDD/> </ZZZ> </BBB> <XXX> <DDD> <EEE/> <DDD/> <CCC/> <FFF/> <FFF> <GGG/> </FFF> </DDD> </XXX> <CCC> <DDD/> </CCC> </AAA> |
Ось descendant-or-self содержит контекстный узел и всех его потомков.
| /AAA/XXX/descendant-or-self::* | //CCC/descendant-or-self::* |
<AAA> <BBB> <CCC/> <ZZZ> <DDD/> </ZZZ> </BBB> <XXX> <DDD> <EEE/> <DDD/> <CCC/> <FFF/> <FFF> <GGG/> </FFF> </DDD> </XXX> <CCC> <DDD/> </CCC> </AAA> |
<AAA> <BBB> <CCC/> <ZZZ> <DDD/> </ZZZ> </BBB> <XXX> <DDD> <EEE/> <DDD/> <CCC/> <FFF/> <FFF> <GGG/> </FFF> </DDD> </XXX> <CCC> <DDD/> </CCC> </AAA> |
Ось ancestor-or-self содержит контекстный узел и всех его предков. Таким образом, эта ось всегда содержит корневой узел.
| /AAA/XXX/DDD/EEE/ancestor-or-self::* | //GGG/ancestor-or-self::* |
<AAA> <BBB> <CCC/> <ZZZ> <DDD/> </ZZZ> </BBB> <XXX> <DDD> <EEE/> <DDD/> <CCC/> <FFF/> <FFF> <GGG/> </FFF> </DDD> </XXX> <CCC> <DDD/> </CCC> </AAA> |
<AAA> <BBB> <CCC/> <ZZZ> <DDD/> </ZZZ> </BBB> <XXX> <DDD> <EEE/> <DDD/> <CCC/> <FFF/> <FFF> <GGG/> </FFF> </DDD> </XXX> <CCC> <DDD/> </CCC> </AAA> |
Оператор div производит деление, оператор mod возвращает остаток от деления нацело. Функция floor - округление до ближайшего целого в сторону увеличения. Функция ceiling - округление до ближайшего целого в сторону уменьшения.
| //BBB[position() mod 2 = 0]
выбрать все BBB, позиция которых кратна 2 |
//BBB[position() = floor(last() div 2 + 0.5) or
position() = ceiling(last() div 2 + 0.5)]
выбрать BBB в середине среди всех BBB (если чётное кол-во BBB, то будут выбраны два) |
//CCC[position() = floor(last() div 2 + 0.5) or
position() = ceiling(last() div 2 + 0.5)]
выбрать CCC в середине среди всех CCC (если чётное кол-во CCC, то будут выбраны два) |
<AAA> <BBB/> <BBB/> <BBB/> <BBB/> <BBB/> <BBB/> <BBB/> <BBB/> <CCC/> <CCC/> <CCC/> </AAA> |
<AAA> <BBB/> <BBB/> <BBB/> <BBB/> <BBB/> <BBB/> <BBB/> <BBB/> <CCC/> <CCC/> <CCC/> </AAA> |
<AAA>
<BBB/>
<BBB/>
<BBB/>
<BBB/>
<BBB/>
<BBB/>
<BBB/>
<BBB/>
<CCC/>
<CCC/>
<CCC/>
</AAA>
|
Всем добра!
Да, всё красиво и просто. Но всё меняется, когда используются namespace-ы...
Спасибо за статью, очень помогла.
Офигенно выручила статья, очень доступно, буду клацать на рекламу пока кнопка не сотрется...
В оригинале этот набор примеров лучше смотрится и воспринимается.
Просто гениально.. перерыл весь инет в поиске что-то типа LIKE и чуть не свихнулся от документаций аля www.w3.org, этопросто вынос мозга.
В этом примере изучение заняли пол минуты отсилы исраз у взакладки !!! низкий поклон
Спасибо БРАТАН! ВЫРУЧИЛ ОТВиЧВАЮ
Очень хорошо! Суть. Сложное состоит из простого.