Получение узлов, имеющих (или не имеющих) дочерний элемент, для применения условного шаблона

Я прочитал много статей, но не нашел окончательного решения своей проблемы.

У меня есть документ XML, к которому я применяю xslt для получения файла csv в качестве вывода. Я отправляю параметр в свое преобразование xsl, чтобы отфильтровать целевые узлы и применить шаблоны.

XML-документ выглядит так (я удалил некоторые ненужные узлы для понимания):

<GetMOTransactionsResponse xmlns="http://www.exane.com/pott" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exane.com/pott PoTTMOTransaction.xsd">
<MOTransaction>
    <Transaction VersionNumber="2" TradeDate="2013-11-20">
        <TransactionId Type="Risque">32164597</TransactionId>
        <InternalTransaction Type="Switch">
            <BookCounterparty>
                <Id Type="Risque">94</Id>
            </BookCounterparty>
        </InternalTransaction>
        <SalesPerson>
            <Id Type="Risque">-1</Id>
        </SalesPerson>
    </Transaction>
    <GrossPrice>58.92</GrossPrice>
    <MOAccount Account="TO1E" />
    <Entity>0021</Entity>
</MOTransaction>
<MOTransaction>
    <Transaction VersionNumber="1" TradeDate="2013-11-20">
        <TransactionId Type="Risque">32164598</TransactionId>
        <SalesPerson>
            <Id Type="Risque">-1</Id>
        </SalesPerson>
    </Transaction>
    <GrossPrice>58.92</GrossPrice>
    <MOAccount Account="TO3E" />
    <Entity>0021</Entity>
</MOTransaction>
</GetMOTransactionsResponse>

Мой xslt ниже (извините, он довольно длинный, и я пишу это проще, чем на самом деле):

 <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:pott="http://www.exane.com/pott">

  <xsl:output method="text" omit-xml-declaration="no" indent="no" />

  <xsl:param name="instrumentalSystem"></xsl:param>

  <xsl:template name="abs">
    <xsl:param name="n" />
    <xsl:choose>
      <xsl:when test="$n = 0">
        <xsl:text>0</xsl:text>
      </xsl:when>
      <xsl:when test="$n &gt; 0">
        <xsl:value-of select="format-number($n, '#')" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="format-number(0 - $n, '#')" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  <xsl:template name="outputFormat">
    <!--Declaration of variables-->
    <xsl:variable name="GrossPrice" select="pott:GrossPrice" />
    <xsl:variable name="TransactionId" select="pott:Transaction/pott:TransactionId[@Type='Risque']" />
    <xsl:variable name="VersionNumber" select="pott:Transaction/@VersionNumber" />

    <!--Set tags values-->
    <xsl:value-of select="$Entity" />
    <xsl:text>;</xsl:text>
    <xsl:value-of select="concat('0000000', pott:MOAccount/@Account) "/>
    <xsl:text>;</xsl:text>

    <xsl:text>;</xsl:text>
    <xsl:value-of select="$TransactionId" />
    <xsl:text>;</xsl:text>
    <xsl:value-of select="$VersionNumber" />
    <xsl:text>&#13;&#10;</xsl:text>
  </xsl:template>
  <xsl:template match="/">
    <xsl:choose>
      <!-- BB -->
      <xsl:when test="$instrumentalSystem = 'BB'">
        <!--xsl:for-each select="pott:GetMOTransactionsResponse/pott:MOTransaction/pott:Transaction[pott:InternalTransaction]"-->
        <xsl:for-each select="pott:GetMOTransactionsResponse/pott:MOTransaction/pott:Transaction[pott:InternalTransaction]">
          <xsl:call-template name="outputFormat"></xsl:call-template>
        </xsl:for-each>
      </xsl:when>

      <!-- CP -->
      <xsl:when test="$instrumentalSystem = 'CP'">
        <xsl:for-each select="pott:GetMOTransactionsResponse/pott:MOTransaction/pott:Transaction[not(pott:InternalTransaction)]">
          <xsl:call-template name="outputFormat"></xsl:call-template>
        </xsl:for-each>
      </xsl:when>

      <xsl:otherwise>
      </xsl:otherwise>
    </xsl:choose>

  </xsl:template>

</xsl:stylesheet>

Если параметр = BB, я хочу выбрать узлы MOTransaction, у которых есть дочерняя транзакция, которая содержит узел InternalTransaction.

Если параметр = CP, я хочу выбрать узлы MOTransaction, у которых нет дочерней транзакции, содержащей узел InternalTransaction

Когда я пишу pott:GetMOTransactionsResponse/pott:MOTransaction/pott:Transaction[pott:InternalTransaction], я получаю узлы Transaction, а не узлы MOTransaction. Я думаю, что я не очень далек от ожидаемого результата, но, несмотря на все мои попытки, я терплю неудачу, Если кто-нибудь может мне помочь.

Я надеюсь, что будет ясно, в противном случае я могу дать больше информации.

1 ответ

Глядя на одно из утверждений xsl:for-each, вы делаете это

<xsl:for-each select="pott:GetMOTransactionsResponse/pott:MOTransaction/pott:Transaction[pott:InternalTransaction]">

Вы говорите, что хотите выбрать элементы MOTransaction, но на самом деле вы выбираете дочерние элементы Transaction. Чтобы соответствовать логике, которую вы требуете, это должно быть

<xsl:for-each select="pott:GetMOTransactionsResponse/pott:MOTransaction[pott:Transaction[pott:InternalTransaction]]">

На самом деле, это также должно работать

<xsl:for-each select="pott:GetMOTransactionsResponse/pott:MOTransaction[pott:Transaction/pott:InternalTransaction]">

Точно так же для второго оператора (в случае параметра "CP") это может выглядеть так:

<xsl:for-each select="pott:GetMOTransactionsResponse/pott:MOTransaction[pott:Transaction[not(pott:InternalTransaction)]]">

Кроме того, это может выглядеть так

<xsl:for-each select="pott:GetMOTransactionsResponse/pott:MOTransaction[not(pott:Transaction/pott:InternalTransaction)]">

Однако они не совсем одинаковы, поскольку первый будет включать только элементы MOTransaction, которые имеют дочерние элементы Transaction, тогда как второй будет включать MOTransaction, у которых вообще нет дочерних элементов Transaction.

Немного в стороне, вам не нужно использовать xsl:for-each и xsl:call-template здесь. Возможно, лучше использовать сопоставление с шаблоном.

Во-первых, попробуйте изменить названный шаблон <xsl:template name="outputFormat"> к этому

<xsl:template match="pott:MOTransaction">

Затем вы можете переписать, объединяя xsl:for-each и xsl:call-template в один вызов xsl:apply-templates.

<xsl:apply-template select="pott:GetMOTransactionsResponse/pott:MOTransaction[pott:Transaction/pott:InternalTransaction]" />
Другие вопросы по тегам