Как избавиться от некорректных атрибутов xmlns в HTML, преобразованном с помощью XSLT

Я пытаюсь преобразовать документ .html с помощью xslt. Сгенерированный html по какой-то причине имеет дополнительный атрибут xmlns в элементе заголовка и пустой атрибут xmlns в элементе заголовка.

example.html:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head><title>foo</title></head>
  <body><h1>bar</h1><img src="baz.jpg" /></body>
</html>

template.xsl:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns="http://www.w3.org/1999/xhtml">

  <xsl:output doctype-system="about:legacy-compat" method="html"
     omit-xml-declaration="yes" />

  <xsl:template match="/html/head">
    <head>
      <meta name="description" content="something added to the head element"/>
      <xsl:apply-templates select="./@*|./node()" />
    </head>
  </xsl:template>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

Я тестировал преобразование с помощью xsltproc и php.

Запуск xsltproc:

$ xsltproc -html template.xsl example.html 
<!DOCTYPE html SYSTEM "about:legacy-compat">
<html xmlns="http://www.w3.org/1999/xhtml">
<head xmlns="http://www.w3.org/1999/xhtml"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="description" content="something added to the head element"></meta><title xmlns="">foo</title></head><body>
<h1>bar</h1>
<img src="baz.jpg">
</body>
</html>

Используя PHP:

<?php

$xmldoc = new DomDocument ();
$xmldoc->loadHTMLFile ("example.html");

$xsldoc = new DomDocument ();
$xsldoc->load ("template.xsl");

$xslt = new XSLTProcessor();
$xslt->importStylesheet($xsldoc);

echo $xslt->transformToXML ($xmldoc);

Я ожидал, что все элементы в исходном документе будут в пространстве имен html, поэтому я не понимаю, почему apply-templates, по-видимому, удаляет пространство имен из элемента title. Я также не понимаю, почему пространство имен html добавлено в элемент head.


person warp    schedule 21.07.2011    source источник
comment
stackoverflow.com/questions/2009980/   -  person Wrikken    schedule 22.07.2011


Ответы (3)


Пространство имен http://www.w3.org/1999/xhtml предназначено для XHTML. Поэтому вы должны установить режим вывода на xml вместо html, а также выводить правильный тип документа для XHTML или вместо этого отображать как html и вообще не использовать какое-либо пространство имен.

Обратите внимание, что XSLT не совсем подходит для создания HTML5, но он идеально подходит для создания HTML 4 или XHTML, если вы уделяете некоторое внимание деталям (например, какие элементы должны или не должны быть пустыми и т. Д.).

person Lucero    schedule 21.07.2011
comment
Переход на ‹xsl: output method = xml›, похоже, решает большинство проблем. Я по-прежнему получаю дополнительный атрибут xmlns в элементе head, но, по крайней мере, он содержит правильное пространство имен, так что это придется делать. Спасибо! - person warp; 23.07.2011

В этом конкретном случае вы должны использовать вид преобразования идентичности, измененный для удаления пространств имен по умолчанию:

<xsl:template match="@*|node()[not(self::*)]">
  <xsl:copy/>
 </xsl:template>

 <xsl:template match="*">
  <xsl:element name="{local-name()}">
   <xsl:apply-templates select="node()|@*"/>
  </xsl:element>
 </xsl:template>

Очевидно, не забудьте удалить эту строку из вашего XSLT:

xmlns="http://www.w3.org/1999/xhtml"

Ваш окончательный шаблон:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output doctype-system="about:legacy-compat" method="html"
        omit-xml-declaration="yes" />

    <xsl:template match="/html/head">
        <head>
            <meta name="description" content="something added to the head element"/>
            <xsl:apply-templates select="./@*|./node()" />
        </head>
    </xsl:template>

    <xsl:template match="@*|node()[not(self::*)]">
        <xsl:copy/>
    </xsl:template>

    <xsl:template match="*">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates select="node()|@*"/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>
person Emiliano Poggi    schedule 21.07.2011
comment
Кажется, это нарушает элементы, которые не должны иметь закрывающего тега. В исходном выводе вы видите ‹img src = baz.jpg› без закрывающего тега, если я использую указанный выше шаблон, я получаю ‹img src = baz.jpg› ‹/img›. - person warp; 22.07.2011
comment
Ваш исходный результат сформирован некорректно. Если вы преобразовываете свои данные, хорошо работающий XSLT-процессор должен закрыть все теги, даже теги HTML, которые не требуют закрывающих тегов. Вы должны быть довольны результатом, показанным в моем ответе :) - person Emiliano Poggi; 22.07.2011
comment
Кроме того, с точки зрения браузера ваша жалоба не актуальна. - person Emiliano Poggi; 22.07.2011
comment
XSLT 2.0 имеет метод вывода XHTML, который будет правильно генерировать элементы XHTML, которые не должны быть самозакрывающимися, например ‹img›. w3.org/TR/xslt-xquery-serialization/#xhtml- вывод - person Mads Hansen; 22.07.2011
comment
@Mads Я думаю, вы ошибаетесь. ВСЕ соответствующие элементы HTML в XHTML должны быть самозакрывающимися. Результирующий эффект, который мы получим с предлагаемой сериализацией, будет примерно <img />, а не <img>. Кроме того, мы добавим к выходным данным ограничения XHTML, а это не то, что ищет OP. - person Emiliano Poggi; 22.07.2011
comment
Вы правы, мой комментарий был неправильным. Я хотел сказать, что вывод XHTML будет делать умные вещи с элементами (например, он знает, что он должен быть <br />, а не <br></br>, <script></script> вместо `‹ script / ›и т. Д. - person Mads Hansen; 22.07.2011

Я не могу объяснить или воспроизвести ваши результаты.

Во-первых, ваш шаблон с match = "/ html / head" не должен соответствовать чему-либо в вашем входном документе, потому что ваши элементы / html / head находятся в пространстве имен.

С Saxon я получаю следующий результат, который я считаю правильным:

<!DOCTYPE html
  SYSTEM "about:legacy-compat">
<html xmlns="http://www.w3.org/1999/xhtml">  
   <head>
      <title>foo</title>
   </head>   
   <body>
      <h1>bar</h1><img src="baz.jpg"></img></body>  
</html>

Итак, либо вы делаете что-то отличное от того, что говорите (например, используете другую таблицу стилей или другой исходный документ, отличный от показанного), либо в используемом вами процессоре XSLT есть ошибка.

person Michael Kay    schedule 22.07.2011
comment
Я также установил пространство имен по умолчанию в таблице стилей, разве это не применимо к элементам в атрибуте соответствия шаблона? - person warp; 22.07.2011