Как идентифицировать пары элементов, которые затем можно преобразовать в непустые элементы с помощью xsl:iterate

Учитывая этот XML, мне нужно заполнить элементы «конец флага» правильным @associatedId, чтобы я мог воссоздать элементы из флагов, используя xsl: iterate. Я знаю, как создавать элементы, но не могу понять, как правильно заполнить @associatedId на конце каждого флага. (Это необходимо из-за того, что мы используем стороннее программное обеспечение. Мне всегда гарантируется равное количество начальных и конечных флагов и что правильное количество конечных флагов будет следовать за правильным количеством начальных флагов.)

    <outer>
        hello
        <flag-start associatedId="test3"/>
        <flag-start associatedId="test"/>
        <span>wor<b>---</b>ld</span>
        <flag-start associatedId="test4"/>
        <flag-end/>
        <flag-start associatedId="test2"/>
        <flag-end/>
        <flag-end/>
        <flag-end/>
        <flag-start associatedId="test5"/>
        <flag-end/>
        some more text
    </outer>

Это желаемый вывод XML:

    <outer>
        hello
        <flag-start associatedId="test3"/>
        <flag-start associatedId="test"/>
        <span>wor<b>---</b>ld</span>
        <flag-start associatedId="test4"/>
        <flag-end associatedId="test4"/>
        <flag-start associatedId="test2"/>
        <flag-end associatedId="test2"/>
        <flag-end associatedId="test"/>
        <flag-end associatedId="test3"/>
        <flag-start associatedId="test5"/>
        <flag-end associatedId="test5"/>
        some more text
    </outer>

person TddOrBust    schedule 06.10.2016    source источник
comment
У вас есть код, который выполняет часть работы? Затем, пожалуйста, покажите его вместе с текущим выходом. Также уточните, какую версию XSLT вы хотите использовать, поскольку xsl:iterate это XSLT 3.0, поэтому, если мы можем использовать ее, уточните это.   -  person Martin Honnen    schedule 06.10.2016


Ответы (1)


Что-то вроде этого:

<xsl:iterate select="*">
  <xsl:param name="stack" select="()"/>
  <xsl:choose>
    <xsl:when test="self::flag-start">
      <xsl:copy-of select="."/>
      <xsl:next-iteration>
        <xsl:with-param name="stack" select="@associatedID, $stack"/>
      </xsl:next-iteration>
    </xsl:when>
    <xsl:when test="self::flag-end">
      <xsl:copy>
        <xsl:attribute name="associatedId" select="head($stack)"/>
      </xsl:copy>
      <xsl:next-iteration>
        <xsl:with-param name="stack" select="tail($stack)"/>
      </xsl:next-iteration>
    </xsl:when>
    <xsl:otherwise>
      <xsl:copy-of select="."/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:iterate>

Не испытано. Предполагается, что данным можно доверять.

person Michael Kay    schedule 06.10.2016
comment
Спасибо, доктор Кей. Это элегантное решение, и я с нетерпением жду дальнейшего использования xsl:iterate. Могу ли я узнать об использовании xsl:copy-of вместо xsl:sequence? Я думал, что последнее (почти) всегда должно быть предпочтительнее первого. - person TddOrBust; 10.10.2016
comment
Я обычно использую xsl:copy-of в таких ситуациях по привычке. В Saxon это не будет иметь никакого значения, если только вы не находитесь внутри функции или переменной. - person Michael Kay; 11.10.2016
comment
Спасибо за объяснение. Я полагал, что Saxon оптимизирует в этом случае. - person TddOrBust; 11.10.2016