@ Кирилл дал правильный ответ относительно того, как исправить
descendant::@*[self::@style]
, используя
//@style
Но для тех, кто хочет знать , почему начальный XPathне работает, и есть ли вариант, использующий self::
, который бы работал ...
Помните, что @
является аббревиатурой для оси attribute::
.Так что self::@foo
является сокращением для self::attribute::foo
.Но синтаксически, в шаге местоположения может быть только одна ось.Вот почему парсер отклоняет self::@style
: у него две оси.
Здесь происходит еще кое-что интересное.Вы можете подумать, что можете исправить выражение следующим образом:
//@*[self::style]
(На данный момент не обращайте внимания на тот факт, что это излишне сложнее, чем //@style
. Вы начинаете пытаться использовать такие выражения, когда вам нужны все атрибуты кроме style
, например //@*[not(self::style)]
.)
Это выражение анализируется и выполняется без ошибок.Первая часть, //@*
, соответствует всем узлам атрибутов в документе.И вы можете подумать (как и я), что предикат [self::style]
будет принимать истинное значение всякий раз, когда его контекстный узел является атрибутом style
.
Но мы были бы неправы.Если мы попробуем это, мы получим пустой набор узлов.Зачем?Если узел контекста является узлом атрибута, а ось self::
содержит только узел контекста, а имя атрибута совпадает с именем, которое следует после self::
, то не должно ли выражение в предикате выводить этот узел атрибута как его результат?
На стр.1228 из XSLT 2.0 и XPath 2.0 (4-е изд.), Определение глоссария Self Axis объясняет:
вид главного узла оси self равен элементов , что означает, что когда узел контекста является атрибутом , ось step формы self::*
или self::xyz
не выберет этот атрибут[жирный акцент мой].
Однако в XPath 2.0 вы можете использовать self::attribute(style)
.То есть вы можете использовать KindTest вместо NameTest.
Майкл Кей подробно расскажет о правилах того, каким типам узлов может соответствовать NameTest на p.695.