Нахождение Направленного графа без петель (DAG) минимальные элементы (вершины) с XSLT/XPath?

Flexbox может сделать это:

.container-fluid {
  display: flex;
  flex-direction: column;
}

.container-fluid * {
  order: 1;
}

.txt {
  order: 2;
}
<section>
  <article class="container-fluid">
    <div class="row">1. Row</div>
    <div class="txt">2. Text</div>
    <div class="gallery">3. Gallery</div>
  </article>
</section>

7
задан Glorfindel 15 March 2019 в 23:03
поделиться

2 ответа

Вы можете воспользоваться преимуществом неявной количественной оценки существования XPath для оператора = :

<xsl:for-each select="//vertex[not(@name = //vertex/directed-edge-to/@vertex)]">

Когда вы используете любой из шести операторов сравнения ( = , ! = , <, <= , > и > = ) для сравнения узла- set, выражение вернет истину, если любой узел в наборе узлов удовлетворяет условию. При сравнении одного набора узлов с другим выражение возвращает истину, если какой-либо узел в первом наборе узлов удовлетворяет условию по сравнению с любым узлом во втором наборе узлов. XPath 2.0 представляет шесть новых операторов, которые не выполняют эту экзистенциальную количественную оценку ( eq , ne , lt , le , gt и ge ). Но в вашем случае вы захотите использовать « = », чтобы получить эту экзистенциальную количественную оценку.

Обратите внимание, конечно, что вы все равно захотите использовать not () работают так же, как и вы. В большинстве случаев рекомендуется избегать оператора ! = . Если вы использовали его здесь вместо not () , тогда он вернет true, если есть какие-либо атрибуты @vertex , которые не равны значению @name . , что не является вашим намерением. (И если какой-либо набор узлов пуст, тогда он вернет false, поскольку сравнения с пустыми наборами узлов всегда возвращают false.)

Если вы хотите использовать вместо этого eq , тогда у вас будет чтобы сделать то же самое, что и вы: отделить условие от итерации, чтобы можно было связать current () . Но в XPath 2.0 вы можете сделать это с помощью выражения:

<xsl:for-each select="for $v in //vertex
                      return $v[not(//directed-edge-to[@vertex eq $v/@name])]">

Это полезно, когда ваше условие не является простым сравнением равенства (и, следовательно, не может быть количественно оценено с помощью " = "). Например: начинается с (@vertex, $ v / @ name) .

XPath 2.0 также имеет явный способ выполнения количественной оценки существования. Вместо приведенного выше выражения для мы могли бы написать следующее:

<xsl:for-each select="//vertex[not(some $e in //directed-edge-to
                                   satisfies @name eq $e/@vertex)]">

В дополнение к синтаксису « some » XPath 2.0 также предоставляет соответствующий « каждый ] "синтаксис для выполнения универсального количественного определения.

Вместо использования для каждого , вы также можете использовать шаблонные правила, которые являются более модульными (и мощными):

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

  <xsl:template match="/">
    <minimal-vertices>
      <xsl:apply-templates/>
    </minimal-vertices>
  </xsl:template>

  <!-- Copy vertex elements that have no arrows pointing to them -->
  <xsl:template match="vertex[not(@name = //directed-edge-to/@vertex)]">
    <minimal-vertex name="{@name}"/>
  </xsl:template>

</xsl:stylesheet>

Опять же , в этом случае мы полагаясь на экзистенциальную количественную оценку = .

XSLT 1.0 запрещает использование функции current () в шаблонах, то есть в атрибуте match , но XSLT 2.0 позволяет это. В этом случае current () относится к узлу, который в настоящее время сопоставляется. Итак, в XSLT 2.0 мы также могли бы написать это (без использования выражения для ):

<xsl:template match="vertex[not(//directed-edge-to[@vertex eq current()/@name])]">

Обратите внимание, что этот шаблон, по сути, такой же, как выражение, которое вы пытались использовать в для - каждый , но хотя он не делает то, что вы хотите в для каждого , он делает то, что вы хотите в шаблоне (потому что то, что current () связывает другое.

Наконец, я добавлю еще один вариант, который в некотором смысле упрощает логику (удаление not () ). Это также относится к использованию XSLT 1.0:

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

  <xsl:template match="/">
    <minimal-vertices>
      <xsl:apply-templates/>
    </minimal-vertices>
  </xsl:template>

  <!-- By default, copy vertex elements -->
  <xsl:template match="vertex">
    <minimal-vertex name="{@name}"/>
  </xsl:template>

  <!-- But strip out vertices with incoming arrows -->
  <xsl:template match="vertex[@name = //directed-edge-to/@vertex]"/>

</xsl:stylesheet>

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

<xsl:template match="text()"/>

Или вы могли бы просто более избирательно подходить к тем узлам, к которым вы применяете шаблоны:

<xsl:apply-templates select="/dag/vertex"/>

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

Я знаю, что пошел дальше того, о чем вы просили, но я надеюсь, что вам это по крайней мере показалось интересным. : -)

<xsl:template match="text()"/>

Или вы могли бы просто более избирательно подходить к тем узлам, к которым вы применяете шаблоны:

<xsl:apply-templates select="/dag/vertex"/>

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

Я знаю, что пошел намного дальше того, о чем вы просили, но я надеюсь, что вы, по крайней мере, нашли это интересным. : -)

<xsl:template match="text()"/>

Или вы могли бы просто более избирательно подходить к тем узлам, к которым вы применяете шаблоны:

<xsl:apply-templates select="/dag/vertex"/>

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

Я знаю, что пошел намного дальше того, о чем вы просили, но я надеюсь, что вы, по крайней мере, нашли это интересным. : -)

8
ответ дан 6 December 2019 в 19:41
поделиться

Одним из таких выражений XPath 1.0 является :

/ * / vertex [not (@name = / * / vertex / direction-edge-to / @ vertex) ]

Затем просто поместите его в таблицу стилей XSLT, подобную этой :

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

    <xsl:template match="/">
      <minimal-vertices>
          <xsl:for-each select=
          "/*/vertex[not(@name = /*/vertex/directed-edge-to/@vertex)]"
          >
           <minimal-vertex name="{@name}"/>
          </xsl:for-each>
      </minimal-vertices>
    </xsl:template>
</xsl:stylesheet>

Когда эта таблица стилей применяется к исходному XML-документу :

<dag>
    <vertex name="A">
        <directed-edge-to vertex="C"/>
    </vertex>
    <vertex name="B">
        <directed-edge-to vertex="C"/>
        <directed-edge-to vertex="D"/>
    </vertex>
    <vertex name="C">
        <directed-edge-to vertex="E"/>
    </vertex>
    <vertex name="D">
        <directed-edge-to vertex="E"/>
    </vertex>
    <vertex name="E">
        <directed-edge-to vertex="G"/>
    </vertex>
    <vertex name="F">
        <directed-edge-to vertex="G"/>
    </vertex>
    <vertex name="G"/>
</dag>

Получен желаемый результат :

<minimal-vertices>
  <minimal-vertex name="A" />
  <minimal-vertex name="B" />
  <minimal-vertex name="F" />
</minimal-vertices>

Обратите внимание : Решение для обхода полных (возможно, циклических) графов доступно в XSLT здесь .

5
ответ дан 6 December 2019 в 19:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: