2015-04-29 1 views
2

Я пытался выяснить, как лучше всего модулизовать таблицы стилей XSLT, чтобы облегчить повторное использование. Я применил идею использования < xsl: apply-import /> как способ введения атрибутов, специфичных для документа, для стандартных преобразований тегов. Это не Работаю так, как я ожидал, и я даже не могу понять, что здесь происходит. Вот упрощенная версия таблицы стилей:Непредвиденное поведение <xsl: apply-import />

<!-- main.xsl --> 
<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:fo="http://www.w3.org/1999/XSL/Format"> 

<xsl:import href="html-customizations.xsl"/> 

<xsl:output method="xml" 
    indent="yes" 
    omit-xml-declaration="no"/> 

<xsl:template match="para"> 
    <fo:block> 
     <xsl:attribute name="space-after">1em</xsl:attribute> 
     <xsl:apply-templates/> 
    </fo:block> 
</xsl:template> 

<!-- =============== --> 
<!-- Inline Elements --> 
<!-- =============== --> 

<xsl:template match="i"> 
    <fo:inline font-style="italic"> 
    <xsl:apply-imports/> 
    <xsl:apply-templates/> 
    </fo:inline> 
</xsl:template> 

<!-- ================ --> 
<!--  Tables  --> 
<!-- ================ --> 

<xsl:template match="table"> 
    <fo:table> 
    <xsl:apply-imports/> 
    <xsl:apply-templates/> 
    </fo:table> 
</xsl:template> 

<xsl:template match="tr"> 
    <fo:table-row> 
    <xsl:apply-imports/> 
    <xsl:apply-templates/> 
    </fo:table-row> 
</xsl:template> 

<xsl:template match="td | th"> 
    <fo:table-cell> 
    <xsl:apply-imports/> 
    <xsl:apply-templates/> 
    </fo:table-cell> 
</xsl:template> 
</xsl:stylesheet> 

Импортированная таблица стилей:

<!-- html-customizations.xsl --> 
<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:fo="http://www.w3.org/1999/XSL/Format"> 

<xsl:template match="td | th"> 
    <xsl:attribute name="hyphenate">true</xsl:attribute> 
</xsl:template> 

</xsl:stylesheet> 

Вот входной XML-файл:

<!-- test.xml --> 
<para> 
    <table> 
    <tr><td>Spongebob Squarepants, <i>Chair</i></td></tr> 
    <tr><td>Patrick Starfish, <i>Vice Cchair</i></td></tr> 
    <tr><td>Squidword, <i>Secretary</i></td></tr> 
    </table> 
</para> 

$ Xalan -o out.xml тест .xml main.xsl

out.xml: 
<?xml version="1.0" encoding="UTF-8"?> 
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" space-after="1em"> 
    <fo:table> 
    <fo:table-row> 
<fo:table-cell hyphenate="true">Spongebob Squarepants, <fo:inline font-style="italic">ChairChair</fo:inline> 
</fo:table-cell> 
<fo:table-cell hyphenate="true">Spongebob Squarepants, <fo:inline font-style="italic">ChairChair</fo:inline> 
</fo:table-cell> 
</fo:table-row> 
    <fo:table-row> 
<fo:table-cell hyphenate="true">Patrick Starfish, <fo:inline font-style="italic">Vice CchairVice Cchair</fo:inline> 
</fo:table-cell> 
<fo:table-cell hyphenate="true">Patrick Starfish, <fo:inline font-style="italic">Vice CchairVice Cchair</fo:inline> 
</fo:table-cell> 
</fo:table-row> 
    <fo:table-row> 
<fo:table-cell hyphenate="true">Squidword, <fo:inline font-style="italic">SecretarySecretary</fo:inline> 
</fo:table-cell> 
<fo:table-cell hyphenate="true">Squidword, <fo:inline font-style="italic">SecretarySecretary</fo:inline> 
</fo:table-cell> 
</fo:table-row> 

    <fo:table-row> 
<fo:table-cell hyphenate="true">Spongebob Squarepants, <fo:inline font-style="italic">ChairChair</fo:inline> 
... 
... 

Как вы можете видеть, каждый дочерний элемент, соответствующий шаблону, который включает в себя < xsl: apply-import />, повторяется! Я включил импортированную таблицу стилей, чтобы проиллюстрировать, что я пытаюсь сделать. Если я закомментировать этот импорт:

<!-- 
<xsl:import href="html-customizations.xsl"/> 
--> 

Повторяющегося поведение такого же:

<?xml version="1.0" encoding="UTF-8"?> 
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" space-after="1em"> 
    <fo:table> 
    <fo:table-row> 
<fo:table-cell>Spongebob Squarepants, <fo:inline font-style="italic">ChairChair</fo:inline>Spongebob Squarepants, <fo:inline font-style="italic">ChairChair</fo:inline> 
</fo:table-cell> 
<fo:table-cell>Spongebob Squarepants, <fo:inline font-style="italic">ChairChair</fo:inline>Spongebob Squarepants, <fo:inline font-style="italic">ChairChair</fo:inline> 
</fo:table-cell> 
</fo:table-row> 
    <fo:table-row> 
... 
... 

без атрибута Я пытаюсь добавить от импортированной таблицы стилей; то есть только наличие инструкции обработки xsl: apply-import /> xsl: apply приводит к удвоению выходных элементов. Также обратите внимание, что это не просто проблема xalan. То же самое происходит на MSXML в Windows 7.

Любые мысли? Я рассчитывал на эту работу, так что теперь я вытаскиваю свои волосы, пытаясь понять, как это исправить, так что это работает.

Кстати, мои предположения о том, как < XSL: Наносить-импорт /> может быть использован основан на примерах, приведенных под XSL: импорт раздел книги Майкла Кея. Если кто-нибудь знает ссылку, объясняющую поведение, которое я вижу выше, пожалуйста, поделитесь.

ответ

4

Я согласен с тем, что поведение apply-imports трудно понять. Проблема в том, что apply-importsвсегда находит шаблон, соответствующий текущему узлу, даже если пользователь не определил его. В этом случае применяется шаблон по умолчанию.

Следующая таблица стилей работы:

таблицы стилей XSLT

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:fo="http://www.w3.org/1999/XSL/Format"> 

    <xsl:import href="html-customizations.xsl"/> 

    <xsl:output method="xml" 
     indent="yes" 
     omit-xml-declaration="no"/> 

    <xsl:template match="para"> 
     <fo:block> 
      <xsl:attribute name="space-after">1em</xsl:attribute> 
      <xsl:apply-templates/> 
     </fo:block> 
    </xsl:template> 

    <!-- =============== --> 
    <!-- Inline Elements --> 
    <!-- =============== --> 

    <xsl:template match="i"> 
     <fo:inline font-style="italic"> 
      <xsl:apply-templates/> 
     </fo:inline> 
    </xsl:template> 

    <!-- ================ --> 
    <!--  Tables  --> 
    <!-- ================ --> 

    <xsl:template match="table"> 
     <fo:table> 

      <xsl:apply-templates/> 
     </fo:table> 
    </xsl:template> 

    <xsl:template match="tr"> 
     <fo:table-row> 

      <xsl:apply-templates/> 
     </fo:table-row> 
    </xsl:template> 

    <xsl:template match="td | th"> 
     <fo:table-cell> 
      <xsl:apply-imports/> 
      <xsl:apply-templates/> 
     </fo:table-cell> 
    </xsl:template> 
</xsl:stylesheet> 

Как вы можете видеть, я удалил два apply-imports элементы, оставив только один внутри template/@match='td | th'.Затем, на выходе будет

XML Output

<?xml version="1.0" encoding="UTF-8"?> 
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" space-after="1em"> 
    <fo:table> 
     <fo:table-row> 
     <fo:table-cell hyphenate="true">Spongebob Squarepants, <fo:inline font-style="italic">ChairChair</fo:inline> 
     </fo:table-cell> 
     </fo:table-row> 
     <fo:table-row> 
     <fo:table-cell hyphenate="true">Patrick Starfish, <fo:inline font-style="italic">Vice CchairVice Cchair</fo:inline> 
     </fo:table-cell> 
     </fo:table-row> 
     <fo:table-row> 
     <fo:table-cell hyphenate="true">Squidword, <fo:inline font-style="italic">SecretarySecretary</fo:inline> 
     </fo:table-cell> 
     </fo:table-row> 
    </fo:table> 
</fo:block> 

Что именно происходит?

apply-imports ищет шаблон, который

  • соответствует текущему узлу
  • соответствует текущему режиму
  • находится внутри импортированной таблицы стилей

Теперь, решающие бито: это команда вызовет built-in templates, если такой шаблон не найден в импортированной таблице стилей. В случае tr:

<xsl:template match="tr"> 
    <fo:table-row> 
    <xsl:apply-imports/> 
    <xsl:apply-templates/> 
    </fo:table-row> 
</xsl:template> 

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

<xsl:template match="tr"> 
    <fo:table-row> 
    <xsl:apply-templates/> 
    <xsl:apply-templates/> 
    </fo:table-row> 
</xsl:template> 

и поэтому вывод содержит дубликаты. Я предполагаю, что теперь вы также понимаете, почему комментирование xsl:import не помогло, в противном случае я рад разработать.


Поскольку вы были просить ссылки, это является объяснено в XSLT 2.0 и XPath 2.0 Справочник программиста Майкл Кей, страница 238.

+0

Спасибо, Матиас - это ответ на мой вопрос. В вашем примере вам также необходимо принять из шаблона 'match =" i "' - обратите внимание, что курсивный текст по-прежнему удваивается; например ChairChair. К сожалению, это не решает мою проблему, так как я хочу, чтобы основная таблица стилей (на самом деле дизайн упрощен для вопроса - на самом деле, есть в промежуточной таблице стилей), которую я хочу использовать полностью неотредактированным. Если мне нужно отредактировать эту таблицу стилей, я могу просто разместить все в шаблонах. – pgoetz

+0

Между тем, я думаю, я подумал о другом способе этого: назовите общие наборы атрибутов для каждого элемента, которые определены во включенной таблице стилей и могут иметь или не иметь никакого содержимого. Я подумаю об этом немного больше, а затем отправлю пример в пользу следующего человека, который приходит с вопросом об этом. Еще раз спасибо! Я думал, что схожу с ума, пытаясь отладить это вчера, так как фактическая таблица стилей довольно длинная и сложная. Мне потребовалось несколько часов, прежде чем я понял, что несет ответственность за мое несчастье. – pgoetz

+0

@pgoetz Вы правы, отредактировал мой ответ, чтобы удалить «apply-import». Не назначать ли атрибуты для элементов не требует также редактирования основной таблицы стилей? –