Примените несколько шаблонов в XSLT 1.0, как XSLT 2.0 - PullRequest
0 голосов
/ 16 апреля 2019

Для приведенного ниже (надуманного) примера HTML:

<div>
  <p>lorem <a href="lorem.html" target="_blank">ipsum</a></p>
  <a href="foo.html" target="top">foo</a>
  <p><img src="foo.jpg" class="bar"/></p>
  <img src="bar.jpg" class="bar"/>
</div>

Я пытаюсь написать преобразование XSLT 1.0, которое:

  • белый список верхнего уровня <p>*Атрибут 1008 *
  • белых списков href для <a>
  • атрибут белых списков src атрибут для <img>
  • оберток верхнего уровня <a> и <img> в <p>...</p>

В идеале это можно сделать способом, позволяющим добавлять больше элементов и атрибутов.

Ожидаемый результат:

<div>
  <p>lorem <a href="lorem.html">ipsum</a></p>
  <p><a href="foo.html">foo</a></p>
  <p><img src="foo.jpg"/></p>
  <p><img src="bar.jpg"/></p>
</div>

Следующий XSLT 2.0 работает благодаря<xsl:next-match>:

Fiddle: https://xsltfiddle.liberty -development.net / 6r5Gh3p :

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:template match="/div">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <!-- whitelist <p> as top-level element -->

  <xsl:template match="/div/p">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <!-- coerce top-level <img> and <a> as children <p> -->

  <xsl:template match="/div/img|/div/a">
    <p><xsl:next-match/></p>
  </xsl:template>

  <!-- whitelist href attribute for <a> -->

  <xsl:template match="a">
    <xsl:copy>
      <xsl:copy-of select="@href"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <!-- whitelist src attribute for <img> -->

  <xsl:template match="img">
    <xsl:copy>
      <xsl:copy-of select="@src"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

В XSLT 1.0 отсутствует <next-match> и использование шаблонаниже соответствует только один раз, поэтому <a> и <img> заключаются в <p>, но их атрибуты не попадают в белый список:

Fiddle: https://xsltfiddle.liberty -development.net / 94rmq6r

  <xsl:template match="/div/img|/div/a">
    <p>
      <xsl:copy><xsl:apply-templates/></xsl:copy>
    </p>
  </xsl:template>

Вывод:

<div>
  <p>lorem <a href="lorem.html">ipsum</a></p>
  <p><a>foo</a></p>
  <p><img src="foo.jpg"/></p>
  <p><img/></p>
</div>

Как это можно сделать в XSLT 1.0?

Ответы [ 2 ]

1 голос
/ 16 апреля 2019

Вы можете использовать xsl:import и xsl:apply-imports здесь.

Для начала вы должны поместить свои шаблоны «белого списка» в отдельный файл XSLT (назовите его «Whitelist.xslt»)

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <!-- whitelist <p> as top-level element -->
  <xsl:template match="/div/p">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <!-- whitelist href attribute for <a> -->
  <xsl:template match="a">
    <xsl:copy>
      <xsl:copy-of select="@href"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <!-- whitelist src attribute for <img> -->
  <xsl:template match="img">
    <xsl:copy>
      <xsl:copy-of select="@src"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Затем ваш основной XSLT может импортировать это, ииспользуйте xsl:apply-imports везде, где вы использовали xsl:next-match

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:import href="Whitelist.xslt" />

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

  <xsl:template match="/div">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <!-- coerce top-level <img> and <a> as children <p> -->
  <xsl:template match="/div/img|/div/a">
    <p><xsl:apply-imports/></p>
  </xsl:template>
</xsl:stylesheet>

В импортированной таблице стилей шаблоны внутри имеют более низкий приоритет, чем шаблоны в основной таблице стилей, поэтому основной шаблон всегда будет соответствовать первому.

РЕДАКТИРОВАТЬ: В качестве отступления ... Я знаю, что ваш пример придуман, но для этого конкретного случая вы можете переписать его без следующих совпадений или применения импорта, например ...

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:template match="/div|/div/p">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

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

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

  <xsl:template match="a/@href|img/@src">
    <xsl:copy />
  </xsl:template>

  <xsl:template match="@*" />
</xsl:stylesheet>
0 голосов
/ 18 апреля 2019

Я думаю, что правильный ответ заключается в том, что в XSLT 1.0 нет эквивалентности для семантики инструкции XSLT 2.0 xsl:next-match.Что как-то ожидается.Из спецификации:

Шаблонное правило, которое используется для переопределения другого шаблонного правила (см. 6.4 Разрешение конфликтов для шаблонных правил ), может использовать xsl:apply-imports или xsl:next-matchинструкция для вызова переопределенного шаблонного правила.Инструкция xsl:apply-imports учитывает только правила шаблона в импортированных модулях таблиц стилей;инструкция xsl:next-match учитывает все другие правила шаблона с более низким приоритетом импорта и / или приоритетом.Обе инструкции вызовут встроенное правило шаблона для узла (см. 6.6 Встроенные правила шаблона ), если не найдено другое правило шаблона.

Итак, сама спецификациядает вам отношение и различие между обеими инструкциями: вы не можете знать, какой шаблон был последним в порядке объявления среди всех тех, которые остались после разрешения конфликта.Также стоит заметить, что импортированные модули таблиц стилей - это не просто форма механизма включения препроцессора Си.Вы можете считать это механизм наследования между преобразованиями.

...