Xpoint
   [напомнить пароль]

copy-of не копирует теги с атрибутом xmlns

2004-05-20 13:57:36 [обр] zenith [досье]

Имеем в 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 полностью копируется со всем содержимым. Где копать?

спустя 1 день 1 час [обр] Эдуард Суров [досье]
zenith[досье]
Так вы же в XPath-запросе namespace не указали, вот он и не выбирает. Попробуйте сделать так:
<xsl:copy-of xmlns:m="http://www.w3.org/1998/Math/MathML" select="//m:math" />
спустя 2 часа 47 минут [обр] Александр Лукьянов [досье]
Вообще-то похоже на баг.
спустя 11 минут [обр] Эдуард Суров [досье]
Александр Лукьянов[досье]
Совершенно не похоже, вполне себе честное поведение. Именно так и должно быть.
<math /> и <math xmlns="..." /> - это два совершенно разных элемента, они находятся в различных пространствах имен, и как раз если XPath-запрос типа //math будет возвращать и то, и другое вперемешку - вот это и будет натуральный баг :)
спустя 51 минуту [обр] Эдуард Суров [досье]
Кстати, namespace'ы, встречающиеся в XML-файле, обычно принято сразу скопом описывать прямо в корневом тэге <stylesheet /> XSL-шаблона, вовсе нет необходимости определять их в каждом XSL-элементе. Главное, чтобы они были заданы в контексте XSL-элемента.
спустя 22 минуты [обр] Александр Лукьянов [досье]

Признаю, был неправ, это не баг, это совершенно законно :)
Вот нашел у М. Кэя очень хорошее объяснение этого заблуждения, позволю себе его привести целиком:

В выражении ХРа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">

Никогда не пользовался пространствами имен без префиксов, как чуял :)

спустя 17 минут [обр] Эдуард Суров [досье]

Александр Лукьянов[досье]
Ну, кстати, это не совсем тот случай :) В случае, который привел zenith[досье], было так:

  1. Перевели <math /> в пространство MathML, выбрали //math (пустое пространство) - ошибка.
  2. Перевели <math /> обратно в пустое пространство, выбрали //math - естественно, сработало.

Фишка в том, что в XSL-шаблоне пространство MathML не было задано, как дефолтное (или zenith[досье] об этом умолчал), поэтому я сразу расценил отсутсвие пространства в XPath-запросе как пустое пространство. А вот приведенный вами пример весьма интересен, я тоже никогда не пытался работать с нэймспейсами по умолчанию и не знал, что XPath их "не видит". Так что если бы zenith[досье] упомянул о, том, что пространство MathML было задано как дефолтное в XSL-шаблоне, проблема аккурат свелась бы к вашей цитате.

спустя 1 час 29 минут [обр] Александр Лукьянов [досье]
Эдуард Суров[досье]
Хм :) Независимо от того указано в XSL пространство имен исходного документа как пространство имен по умолчанию или нет, выражение //math не выберет ничего.
Ведь объявление пространства имен по умолчанию в XSL, насколько я понимаю, означает, что в это пространство имен попадают конечные литеральные элементы, находящиеся в самой таблице стилей, но совсем не означает, что в выражениях XPath имена без префиксов принадлежат к этому пространству имен, о чем Кэй и пишет. Если не указать в XSLT дефолтного пр-ва имен, то конечные литеральные элементы будут иметь пустое пространство имен, только и всего - на принадлежность имен без префиксов в выражениях XPath к какому-либо пространству имен это не отразится никак.
Иначе говоря, единственный способ в XSLT в выражениях XPath "достучаться" до элементов из исходного документа, привязанных к непустому пространству имен по умолчанию в исходном документе, — это явно указать в XSLT какой-либо префикс для default namespace исходного документа и в выражениях XPath использовать этот префикс, согласны?
спустя 10 минут [обр] Александр Лукьянов [досье]
Хотя, конечно, можно еще *[name()='...' and namespace-uri()='...'] использовать, но это изврат :)
спустя 1 час 5 минут [обр] Andy Taler [досье]

Согласно 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:" [или любой др. префикс на выбор] нигде более в стиле не будет упомянут.

спустя 8 часов [обр] zenith [досье]
Спасибо вам огромное! Сработало и, благодаря вашим рассуждениям (даже не думал, что их будет так много), понял ошибку :)
Powered by POEM™ Engine Copyright © 2002-2005