Сделан по двум книгам. "Самоучитель XML" и "XSLT сборник рецептов". Здесь я "адаптировал" почти все примеры для HTML и выполнил их, используя библиотеку lxml. Не хватило терпения на примеры фильтров, я просто скопировал их из книги...
Помним, что строки запросов строятся по принципу Ось::Тест узла[Предикат]¶
#Тест по имени узла (axis)
/ #Узел документа (нет в списке осей)
self:: #
child:: #Прямой потомок
descendant:: #Все потомки
descendant-or-self:: #
following:: # ниже (по тексту)
following-sibling::
preceding:: # выше (по тексту)
preceding-sibling::
parent:: #
ancestor:: #
ancestor-or-self:: #
attribute:: #
#Тест по виду узла
node() # Узел любого вида
text() # Текстовый узел
comment() # Узлы-комментарии
element() # =element(*) = element(*,*)
element(name,type) # Все узлы с именем name
attribute() # =attribute(@*) = attribute(@*,*)
attribute(@name)
attribute(@name,type)
processing-instruction()
processing-instruction(name) #Отбирает все инструкции по обработке с имененм обрабатывающей программы name
document-node()
document-node(element(args))
# Сокращения
// #= descendant-or-self::node()/
attribute::* #= attribute::node()
namespace::* #= namespace::node()
axis::* #= axis::element() (axis - любая ось)
* #= child::element()
@ #= attribute:: (@href, @*,)
. #= self::node()
.. #= parent::node()
# Предикат - True / False
[1] #= [position()=1] Первый найденный узе[last()-1] #= предпоследний узел
AAA/BBB/CCC[last()-1] #Предпоследний из элементов ССС, вложенных в BBB
//*[count(CCC)=2] #Все элементы документа с двумя вложенными CCC
/*[count(CCC)=2] #Все элементы документа с двумя любыми вложенными элементами
//DDD[@name] #Все DDD c атрибутом name
//DDD@id="3"] # DDD c атрибутом id="3"
//DDD[not(@name)] #Все DDD без атрибута name
Далее повторяем примеры (1.1. Применение осей) из книги XSLT сборник рецептов¶
Для работы с XPath c с кодом из In [5]
from lxml import html in1=html.fromstring(In[89])
Оси потомков¶
<div id="descendants">
<div class="parent">
<span class="x" id="1"/>
<span class="x" id="2"/>
<p class="y" id="3">
<span class="x" id="3-1"/>
<p class="y" id="3-2"/>
<span class="x" id="3-3"/>
</p>
<span class="x" id="4"/>
<p class="y" id="5"/>
<p class="z" id="6"/>
<span class="x" id="7"/>
<span class="x" id="8"/>
<p class="y" id="9"/>
</div>
</div>
#Дочерняя ось принимается в XPath по умолчанию. Иными словами, явно указывать ось
child::
#необязательно, но, если вы хотите быть педантом, то можете
# указать. Спуститься по XML дереву глубже, чем на один уровень, позволяют
#оси
descendant::
#и
descendant or self::
#Первая не включает сам контекстный узел, вторая – включает.
in1.xpath('span') , in1.xpath('*/span/@id'), in1.xpath('//span/@id')
# // = descendant-or-self::node()/
# * = child::element()
#Отображать второй дочерний элемент
in1.xpath('*/span[2]/@id'), in1.xpath('//span[2]/@id')
in1.xpath('*/span[last()-2]/@id') # Последний элемент
in1.xpath('//span[2][self::span]/@id'), in1.xpath('//span/@id') # [self::span] - При условии, что элемент называется span
# Отображать всех потомков (и внуков)
in1.xpath('div/@id'), in1.xpath('div/div/@class')
in1.xpath('*/div/descendant::p/@id') # Все потомки с именем 'p' во вложеном теге div
in1.xpath('div/descendant::p/@id') # Все потомки с именем 'p' в корневом теге div
Оси братьев¶
in2=html.fromstring(In[40])
<div id="preceding-siblings">
<span id="1"/>
<span id="2"/>
<p id="3"/>
<span id="4"/>
<p id="5"/>
<br id="6"/>
<span id="7"/>
<span id="8"/>
<p id="9"/>
</div>
# Отображать всех братьев-предшественников с именем span
in2.xpath('//span[4]/@id'), in2.xpath('//span[4]/preceding-sibling::span/@id')
# Отображать всех братьев-предшественников с именем p
# и вместо номера по порядку условие с id
in2.xpath('//span[@id="7"]/@id'), in2.xpath('//span[@id="7"]/preceding-sibling::p/@id')
# братья - последователи с именем span
in2.xpath('//span[@id="7"]/@id'), in2.xpath('//span[@id="7"]/following-sibling::span/@id')
# последователи с именем * (любым)
in2.xpath('//span[@id="7"]/@id'), in2.xpath('//span[@id="7"]/following-sibling::*/@id')
# Отображать ближайшего (первого) братьев-предшественников с именем span
# cмотри In [51] - там все братья
in2.xpath('//span[4]/@id'), in2.xpath('//span[4]/preceding-sibling::span[1]/@id')
# Отображать ближайшего (первого) братьев-предшественников
# при условии, что его имя span
# cмотри In [51] - там все братья
in2.xpath('//span[4]/@id'), in2.xpath('//span[4]/preceding-sibling::*[1][self::span]/@id')
# Отображать ближайшего (первого) братьев-предшественников
# при условии, что его имя br
# cмотри In [51] - там все братья
in2.xpath('//span[4]/@id'), in2.xpath('//span[4]/preceding-sibling::*[1][self::br]/@id')
# Отображать братьев-предшественников
# при условии, что они не span
# cмотри In [51] - там все братья
in2.xpath('//span[4]/@id'), in2.xpath('//span[4]/preceding-sibling::*[not(self::span)]/@id')
Далее снова будем использовать пример
print In[89]
# Первый брат сверху при условии, что у него есть дочка span
in1.xpath('//span[@id="4"]/@id'), in2.xpath('//span[@id="4"]/preceding-sibling::*[1][span]/@id')
preceding-sibling::*[1][A] # Пример выше не получился ...
# Первый брат сверху при условии, что его зовут span
in1.xpath('//span[4]/@id'), in2.xpath('//span[4]/preceding-sibling::p[p][2]/@id')
# Пример выше не получился ...
Родительская ось и ось предков¶
Родительская ось (parent::) относится к родителю контекстного узла.
Первое порождает последовательность, которая содержит в точности один элемент, если имя родителя контекстного узла – X, и пуста в противном случае. Второе – это сокращенная запись выражения parent::node()/X , которое отбирает всех братьев контекстного узла с именем X, в том числе и сам этот узел, если он называется X. С помощью осей ancestor:: ancestor or self:: можно перемещаться вверх по XML дереву (переходя к родителю, деду, прадеду и т.д.). В первом случае сам контекстный узел исключается, во втором – включается.
#Не путайте выражение
parent::X #îçâðàùàåò ðîäèòåëÿ êîíòåêñòíîãî óçëà, ïðè óñëîâèè, ÷òî îí íàçûâàåòñÿ
X, â ïðîòèâíîì ñëó÷àå – ïóñòóþ ïîñëåäîâàòåëüíîñò
#с
../X
print In[89]
in1.xpath('//span[@id="3-1"]/@id'), in1.xpath('//span[@id="3-1"]/parent::node()/@id')
in1.xpath('//span[@id="3-1"]/@id'), in1.xpath('//span[@id="3-1"]/parent::p/@id'), in1.xpath('//span[@id="3-1"]/parent::*/@id')
in1.xpath('//span[@id="3-1"]/@id'), in1.xpath('//span[@id="3-1"]/ancestor::p/@id'), in1.xpath('//span[@id="3-1"]/ancestor::*/@id')
in1.xpath('//p[@id="3"]/ancestor-or-self::*/@id'), in1.xpath('//p[@id="3"]/ancestor-or-self::*/span/@id'),
Оси предшественников и последователей¶
in1.xpath('//span[@id="4"]/preceding::*/@id'), in1.xpath('//span[@id="4"]/preceding::p/@id')
in1.xpath('//span[@id="4"]/preceding::p[2]/@id'), in1.xpath('//span[@id="4"]/preceding::p[last()-1]/@id')
Фильтрация узлов стр.27 XSLT сборник рецептов¶
# У всех кроме div, по два атрибута, поэтому фильтровать
# по количесвтву атрибутов нечего, но можно
in1.xpath('//span[@*]/@id'), in1.xpath('//span[count(@*) >= 2]/@id'), in1.xpath('//div[count(@*) >= 2]/@id')
[not(@*)]
X[@a eq '10']
X[Z eq '10']
X[Z ne '10']
X[text()]
X[text()][normalize-space(.)]
X[node()]
X[comment()]
X[number(@a) < 10]
X[preceding-sibling::Z/@y ne '10']
X[. = ' ']
X[false()]
X[true()]
X[count(*) eq 5]
X[count(node()) eq 5]
X[count(@*) | node()) eq 5]
X[1][. eq 'some text']
X[. eq 'some text'][1]
Выше примеры фильтров описния к которым можно посмотреть по ссылке в заголовке раздела
Посты чуть ниже также могут вас заинтересовать
Комментариев нет:
Отправить комментарий