XSLT1.0 Проверьте, существует ли потомок, у которого у предков нет определенного атрибута, но если он есть, его значение должно быть в переменной RTF - PullRequest
2 голосов
/ 03 апреля 2012

У меня есть xsl:variable ($ features-list), указанный в моем XSL, который содержит фрагмент дерева из внешнего XML-файла.

<xsl:variable name="features-list" select="document('features-list.xml', /)" />

Этот файл содержит список элементов «feature», где значение каждого элемента указывает имя элемента. В XML, который я пытаюсь преобразовать (это на самом деле схема RNG), некоторые элементы имеют атрибуты, которые обычно называются «if-feature», которые указывают, что копия такого элемента (или, скорее, всего поддерева) должна появляться только в преобразованном документ, если такой атрибут отсутствует, ИЛИ, если атрибут появляется, но имеет то же значение, что и один из элементов объекта во внешнем файле. Это может потенциально означать, что целые поддеревья могут быть опущены в результирующем документе, поскольку атрибут «унаследован» от предков.

Я успешно использовал эту переменную для запуска или пропуска определенных шаблонов, используя проверки типа

<xsl:when test="not(@if-feature) or @if-feature and $features-list//*[.=current()/@if-feature]">
</xsl:when>

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

<xsl:apply-templates select="descendant::foo[ancestor-or-self::*[not(@if-feature) or $features-list//*[.=current()/@if-feature]]]"/>

где current () относится к одному из элементов предка или самого себя. Я на самом деле пытаюсь запустить шаблон, основанный на условии, как это: обрабатывать только потомки foo текущего узла, предки (и самого себя) - если у них есть атрибут if-feature - его значение должно соответствовать одному из элемента Feature значения в $ feature-list.

Могу ли я выразить такое условие, используя только XPath? Как?

Будет ли решение XSLT более подходящим здесь? Это идентифицирует нарушающие элементы, но мне не очень помогает из-за ограничений XSLT.

<xsl:for-each select="descendant::foo">
    <xsl:for-each select="ancestor-or-self::*">
      <xsl:choose>
        <xsl:when test="@if-feature and not($features-list//*[.=current()/@if-feature])">
          <!-- we have a hit, break and do not proceed - but wait, this is XSLT, not Java -->
        </xsl:when>
      </xsl:choose>
    </xsl:for-each>
 </xsl:for-each>

Стараюсь изо всех сил изучать XSLT 1.0 здесь, поэтому, пожалуйста, воздержитесь от предоставления решений для 2.0.

То, что я пытаюсь сделать, - это извлечь действующую схему ГСЧ из существующей, которая задает поддеревья на основе возможностей. Я на самом деле уже сделал это, но это не работает для ONE крошечного небольшого редкого случая, который сейчас сводит меня с ума. Сквозь стены огня. И кирпичи.

Редактировать: спецификация моего состояния была неясной, поэтому я исправил ее.

1 Ответ

2 голосов
/ 03 апреля 2012
<xsl:apply-templates select="
  .//foo[not(
    ancestor-or-self::*[
      @if-feature and not( @if-feature = $features-list//text() )
    ]
  )]
"/>

Оператор XPath = сравнивает каждый узел в наборе узлов и выдает true, если один из узлов выполняет сравнение.Поэтому просто сравните @if-feature с набором узлов.

Общие замечания.

  • XSLT основан на декларативном выборе правильных узлов для обработки и сопоставления с шаблоном.Это довольно хорошо в этом.Это не хорошо с подходом императивного программирования, поэтому постарайтесь перестать думать о Java.
  • Попробуйте отбросить <xsl:for-each>.Большую часть времени это приносит больше вреда, чем пользы.Вместо этого используйте <xsl:apply-templates> и <xsl:template>.
  • Предпочитайте выбирать правильные узлы над , выбирая все узлы - если вы не хотите обрабатывать все узлы.
  • После выбора узлов вы не можете остановить цикл.Но вы можете решить, будет ли выполнено его тело.

Например, в алфавитном порядке сначала @if-feature:

<xsl:for-each select="descendant::foo">
  <xsl:sort select="@if-feature" data-type="text" />
  <xsl:if test="position() = 1">
    <!-- ... -->
  </xsl:if>
</xsl:for-each>

Это не совсем то же самое, чтоточка останова, но она имеет тот же эффект.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...