Переопределение шаблона при выполнении сложных условий - PullRequest
1 голос
/ 17 октября 2019

У меня есть некоторый XML, который семантически аналогичен приведенному ниже:

<root>
  <parent>
    <a>
      <b t="0"/>
    </a>
    <a>
      <b t="0"/>
    </a>
    <a so="2">
      <b t="1">
        <c n="x"/>
      </b>
    </a>    
    <a>
      <b t="2">
        <c n="x"/>
      </b>
    </a>
    <a>
      <b t="1">
        <c n="y"/>
      </b>
    </a>
    <a so="3">
      <b t="2">
        <c n="z"/>
      </b>
   </a>
  </parent>
  <parent>
    <a so="1">
      <b t="2">
        <c n="x"/>
      </b>
    </a>
    <a so="4">
      <b t="1">
        <c n="z"/>
      </b>
    </a>
  </parent>
</root>

И у меня есть шаблон, который применяется ко всем a элементам:

<xsl:template match="a" mode="whatever">
  do some nice stuff with the content of a
</xsl:template>

У меня есть некоторыешаблоны, которые переопределяют поведение, ничего не делая, если выполняются определенные условия. например:

<xsl:template match="a[@t='0'][preceding-sibling:a[@t='0']" mode="whatever">
<!-- ignore this node entirely -->
</xsl:template>

(обратите внимание, в приведенном выше примере порядок документов имеет значение, в вопросе ниже он не имеет значения)

Что прекрасно работает, однако теперь мне нужно сделать что-то более сложное,Я хочу игнорировать 4-й a элемент в приведенном выше примере xml, учитывая, что выполняются следующие условия:

  • b/@t="2"
  • есть некоторые другие a в пределахтот же родительский элемент, где b/@t="1"
  • значения b/c/@n одинаковы для обоих элементов a.

В примере xml последний узел не должен совпадатьпо этому правилу, так как значения @n разные.

Мне все равно, в каком порядке находятся a узлы, или между ними есть другие вещи. Однако я могу утверждать, что узлы будут в указанном порядке, без промежуточных узлов, если это необходимо.

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

В настоящее время я использую xmlstarlet, который не поддерживает XSLT2.0 или XPATH2.0, я могу исследовать другие механизмы, но предпочел бы придерживаться того, чтоЯ имею, если это вообще возможно.

NB Узел в разных parent узлах не должен влиять друг на друга - например, на узел, помеченный @so=1, не должно влиять присутствие узла, помеченного @so=2, поскольку онинаходятся в разных родительских узлах. Аналогично для @so=3 и @so=4. В примере ни один из этих узлов не должен совпадать

1 Ответ

1 голос
/ 17 октября 2019

Следующий фрагмент XSLT удаляет 4-й a в соответствии с запросом:

<!-- all a keyed by the value of b/@t -->
<xsl:key name="k1" match="//parent/a" use="b/@t"/>

<xsl:template match="//parent/a[b/@t = 2 and
                     key('k1', 1)/b/c/@n = b/c/@n]"/>

Предложение соответствия выбирает все a, имеющие b/@t = 2. Затем он проверяет, существует ли a, где b/@t = 1, имеющее то же значение для b/c/@n, что и текущий элемент.

Если проверка должна выполняться только в пределах одного и того же родителя, вы можете добавить идентификаторродительский ключ для ключа:

<!-- all a keyed by parent node and the value of b/@t -->
<xsl:key name="k1" match="//parent/a" use="concat(generate-id(..),'|',b/@t)"/>

<xsl:template match="//parent/a[b/@t = 2 and
                     key('k1', concat(generate-id(..),'|',1))/b/c/@n = b/c/@n]"/>

Последний скрипт XSLT преобразует следующий XML:

<root>
  <parent>
    <a>       <b t="0"/></a>
    <a>       <b t="0"/></a>
    <a so="2"><b t="1"><c n="x"/></b></a>
    <a>       <b t="2"><c n="x"/></b></a>
    <a>       <b t="1"><c n="y"/></b></a>
    <a so="3"><b t="2"><c n="z"/></b></a>
  </parent>
  <parent>
    <a so="1"><b t="2"><c n="x"/></b></a>
    <a so="4"><b t="1"><c n="z"/></b></a>
  </parent>
</root>

в

<root>
  <parent>
    <a>       <b t="0"/></a>
    <a>       <b t="0"/></a>
    <a so="2"><b t="1"><c n="x"/></b></a>

    <a>       <b t="1"><c n="y"/></b></a>
    <a so="3"><b t="2"><c n="z"/></b></a>
  </parent>
  <parent>
    <a so="1"><b t="2"><c n="x"/></b></a>
    <a so="4"><b t="1"><c n="z"/></b></a>
  </parent>
</root>
...