copy-of не копирует теги с атрибутом xmlns
Имеем в example.xml:
<math xmlns="http://www.w3.org/1998/Math/MathML">
<!-- Содержимое -->
</math>
В example.xsl:
<xsl:copy-of select="//math" />
При преобразовании mozilla или xsltproc полностью "съедается" тег math со всем содержимым. Если же убрать атрибут xmlns="http://www.w3.org/1998/Math/MathML", тег math полностью копируется со всем содержимым. Где копать?
Так вы же в XPath-запросе namespace не указали, вот он и не выбирает. Попробуйте сделать так:
<xsl:copy-of xmlns:m="http://www.w3.org/1998/Math/MathML" select="//m:math" />
Совершенно не похоже, вполне себе честное поведение. Именно так и должно быть.
<math /> и <math xmlns="..." /> - это два совершенно разных элемента, они находятся в различных пространствах имен, и как раз если XPath-запрос типа //math будет возвращать и то, и другое вперемешку - вот это и будет натуральный баг :)
Признаю, был неправ, это не баг, это совершенно законно :)
Вот нашел у М. Кэя очень хорошее объяснение этого заблуждения, позволю себе его привести целиком:
В выражении ХРаth полное имя без префикса использует пустой URI пространства имен, а не URI пространства имен по умолчанию.
Незнание этого факта является распространенной ошибкой. Представим, что исходный документ начинается так:<html xmlns="http://www.w3.org/1999/xhtml">а таблица стилей - так:
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" version="1.0"> <xsl:template match="html">Почему шаблонное правило «match="html"» не срабатывает, когда в документе встречается элемент <html>? Потому что пространство имен по умолчанию (объявленное при помощи атрибута «xmlns="..."») относится только к полным именам без префикса из исходного документа, но не к полным именам без префикса, находящихся в выражениях и образцах соответствия таблицы стилей. Фрагмент таблицы стилей необходимо переписать следующим образом:
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml" version="1.0"> <xsl:template match="xhtml:html">
Никогда не пользовался пространствами имен без префиксов, как чуял :)
Александр Лукьянов[досье]
Ну, кстати, это не совсем тот случай :) В случае, который привел zenith[досье], было так:
- Перевели
<math />в пространство MathML, выбрали//math(пустое пространство) - ошибка. - Перевели
<math />обратно в пустое пространство, выбрали//math- естественно, сработало.
Фишка в том, что в XSL-шаблоне пространство MathML не было задано, как дефолтное (или zenith[досье] об этом умолчал), поэтому я сразу расценил отсутсвие пространства в XPath-запросе как пустое пространство. А вот приведенный вами пример весьма интересен, я тоже никогда не пытался работать с нэймспейсами по умолчанию и не знал, что XPath их "не видит". Так что если бы zenith[досье] упомянул о, том, что пространство MathML было задано как дефолтное в XSL-шаблоне, проблема аккурат свелась бы к вашей цитате.
Хм :) Независимо от того указано в XSL пространство имен исходного документа как пространство имен по умолчанию или нет, выражение
//math не выберет ничего.Ведь объявление пространства имен по умолчанию в XSL, насколько я понимаю, означает, что в это пространство имен попадают конечные литеральные элементы, находящиеся в самой таблице стилей, но совсем не означает, что в выражениях XPath имена без префиксов принадлежат к этому пространству имен, о чем Кэй и пишет. Если не указать в XSLT дефолтного пр-ва имен, то конечные литеральные элементы будут иметь пустое пространство имен, только и всего - на принадлежность имен без префиксов в выражениях XPath к какому-либо пространству имен это не отразится никак.
Иначе говоря, единственный способ в XSLT в выражениях XPath "достучаться" до элементов из исходного документа, привязанных к непустому пространству имен по умолчанию в исходном документе, — это явно указать в XSLT какой-либо префикс для default namespace исходного документа и в выражениях XPath использовать этот префикс, согласны?
*[name()='...' and namespace-uri()='...'] использовать, но это изврат :)
Согласно XPath-1.0 спецификации, если в XPath элементы указаны простыми именами (без префикса), эти элементы с точки зрения XPath не считаются находящимися в каком-либо пространстве имен (невзирая, какие и где умалчиваемые пространства имеются).
Поэтому в XPath-1.0 выход всего один: для элементов из xml-файла, находящихся в умалчиваемом(ых) пространстве, чтобы в xslt-стиле работали XPath-выражения, необходимо ввести ФИКТИВНЫЙ префикс (с нужным URI), просто для того, дабы можно было воспользоваться в XPath-выражениях этим префиксом. И неважно, введете вы этот префикс в xsl:stylesheet (вверху, как у Кэя) или именно так, как предлагал Эдуард Суров:
(и в его варианте все аналогично и замечательно должно работать):
<xsl:copy-of xmlns:m="http://www.w3.org/1998/Math/MathML" select="//m:math" />
- даже если этот "m:" [или любой др. префикс на выбор] нигде более в стиле не будет упомянут.
![[logo]](/site/images/logo.jpg)