2013-05-28 2 views
1

Я пытаюсь получить значения из предыдущих элементов. Но значение, которое я пытаюсь восстановить, должно быть после определенной позиции и перед другой позицией узлов. Как я могу это сделать?Получить значение между позициями узлов XML

Пример XML:

<?xml version="1.0" encoding="UTF-8"?> 
<actions> 
    <action> 
     <code>tr</code> 
     <value>503</value> 
    </action> 
    <action> 
     <code>co</code> 
     <value>0</value> 
    </action> 
    <action> 
     <code>cou</code> 
     <value>0</value> 
    </action> 
    <action> 
     <code>tr</code> 
     <value>87</value> 
    </action> 
    <action> 
     <code>st</code> 
     <value>0</value> 
    </action> 
    <action> 
     <code>wta</code> 
     <value>0</value> 
    </action> 
    <action> 
     <code>pi</code> 
     <value>0</value> 
    </action> 
    <action> 
     <code>tr</code> 
     <value>64</value> 
    </action> 
    <action> 
     <code>st</code> 
     <value>0</value> 
    </action> 
    <action> 
     <code>del</code> 
     <value>0</value> 
    </action> 
    <action> 
     <code>tr</code> 
     <value>27</value> 
    </action> 
    <action> 
     <code>wa</code> 
     <value>0</value> 
    </action> 
    <action> 
     <code>dec</code> 
     <value>0</value> 
    </action> 
</actions> 

Текущий XSLT:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="xs fn"> 
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 

    <xsl:template match="/actions"> 
     <result> 
      <!-- Loop through all action elements --> 
      <xsl:for-each select="action"> 
       <!-- Display only the needed action in the result file --> 
       <xsl:if test="code = 'co' or code = 'st' or code = 'dec' or code = 'pi' or code = 'del'"> 
        <action> 
         <code> 
          <xsl:choose> 
           <xsl:when test="code = 'co'">1</xsl:when> 
           <xsl:when test="code = 'st'">5</xsl:when> 
           <xsl:when test="code = 'dec'">2</xsl:when> 
           <xsl:when test="code = 'pi'">3</xsl:when> 
           <xsl:when test="code = 'del'">4</xsl:when> 
          </xsl:choose> 
         </code> 
         <!-- Get some positions in variables --> 
         <xsl:variable name="previousPosition"><xsl:value-of select="position() - 1" /></xsl:variable> 
         <xsl:variable name="lastTRPosition"><xsl:value-of select="count((preceding::action[code = 'tr'])[last()]/preceding::action)+1" /></xsl:variable> 
         <xsl:variable name="currentPosition"><xsl:value-of select="position()" /></xsl:variable> 
         <!-- Should be the value of the preceding action element with code 'tr' (last occurence). But only use when between the last preceding action element with code 'tr' and the current node position NO known code is used ('co', 'st', 'dec', 'pi' or 'del') --> 
         <value> 
            <xsl:choose> 
             <xsl:when test="(preceding::action[code = 'tr']/value)[last()] != ''"> <!-- some work to do here --> 
              <xsl:value-of select="round((preceding::action[code = 'tr']/value)[last()])" /> 
             </xsl:when> 
             <xsl:otherwise>0</xsl:otherwise> 
            </xsl:choose> 
         </value> 
        </action> 
       </xsl:if> 
      </xsl:for-each> 
     </result> 
    </xsl:template> 
</xsl:stylesheet> 

Текущий результат:

<?xml version="1.0" encoding="UTF-8"?> 
<result> 
    <action> 
     <code>1</code> 
     <value>503</value> 
    </action> 
    <action> 
     <code>5</code> 
     <value>87</value> 
    </action> 
    <action> 
     <code>3</code> 
     <value>87</value> 
    </action> 
    <action> 
     <code>5</code> 
     <value>64</value> 
    </action> 
    <action> 
     <code>4</code> 
     <value>64</value> 
    </action> 
    <action> 
     <code>2</code> 
     <value>27</value> 
    </action> 
</result> 

Требуются результат:

<?xml version="1.0" encoding="UTF-8"?> 
<result> 
    <action> 
     <code>1</code> 
     <value>503</value> 
    </action> 
    <action> 
     <code>5</code> 
     <value>87</value> 
    </action> 
    <action> 
     <code>3</code> 
     <value>0</value> 
    </action> 
    <action> 
     <code>5</code> 
     <value>64</value> 
    </action> 
    <action> 
     <code>4</code> 
     <value>0</value> 
    </action> 
    <action> 
     <code>2</code> 
     <value>27</value> 
    </action> 
</result> 

изменения и почему?

<action> 
    <code>3</code> 
    <value>87</value> <!-- should be 0 --> 
</action> 

Это должен быть 0. Поскольку между положением последнего action/code = 'tr' и текущей позицией() узлом, чтобы писать в результате известного кода «St», который уже имеет это значение.

<action> 
    <code>4</code> 
    <value>64</value> 
</action> 

Это должен быть 0. Поскольку между положением последнего action/code = 'tr' и текущей позицией() узлом, чтобы писать в результате известного кода «St», который уже имеет это значение.

Я немного застрял в получении правильного теста в xsl:when. Может ли кто-нибудь помочь?

ответ

1

Я предлагаю сгруппировать с помощью group-starting-with, а затем для использования фильтра >>. Я также сделал отображение параметра и используется ключ к карте эффективно, поэтому в целом я получаю

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="xs fn"> 

    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 

    <xsl:key name="code" match="code" use="@from"/> 

    <xsl:param name="code-map"> 
     <code from="co" to="1"/> 
     <code from="st" to="5"/> 
     <code from="dec" to="2"/> 
     <code from="pi" to="3"/> 
     <code from="del" to="4"/> 
    </xsl:param> 

    <xsl:template match="/actions"> 
     <result> 
      <xsl:for-each-group select="action" group-starting-with="action[code = 'tr']"> 
       <xsl:variable name="tr-head" select="."/> 
       <xsl:apply-templates select="current-group()[self::action[code = $code-map/code/@from]]"> 
       <xsl:with-param name="tr" select="$tr-head"/> 
       </xsl:apply-templates> 
      </xsl:for-each-group> 
     </result> 
    </xsl:template> 

    <xsl:template match="action"> 
     <xsl:param name="tr"/> 
     <xsl:copy> 
     <code> 
      <xsl:value-of select="key('code', code, $code-map)/@to"/> 
     </code> 
     <value> 
      <xsl:value-of 
      select="if (not(exists((current-group() except $tr) 
            [current() >> . and code = $code-map/code/@from]))) 
        then $tr/value else 0"/> 
     </value> 
     </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

Когда я Saxon 9,5 превратить вход

<?xml version="1.0" encoding="UTF-8"?> 
<actions> 
    <action> 
     <code>tr</code> 
     <value>503</value> 
    </action> 
    <action> 
     <code>co</code> 
     <value>0</value> 
    </action> 
    <action> 
     <code>cou</code> 
     <value>0</value> 
    </action> 
    <action> 
     <code>tr</code> 
     <value>87</value> 
    </action> 
    <action> 
     <code>st</code> 
     <value>0</value> 
    </action> 
    <action> 
     <code>wta</code> 
     <value>0</value> 
    </action> 
    <action> 
     <code>pi</code> 
     <value>0</value> 
    </action> 
    <action> 
     <code>tr</code> 
     <value>64</value> 
    </action> 
    <action> 
     <code>st</code> 
     <value>0</value> 
    </action> 
    <action> 
     <code>del</code> 
     <value>0</value> 
    </action> 
    <action> 
     <code>tr</code> 
     <value>27</value> 
    </action> 
    <action> 
     <code>wa</code> 
     <value>0</value> 
    </action> 
    <action> 
     <code>dec</code> 
     <value>0</value> 
    </action> 
</actions> 

я получаю желаемого результата

<result> 
    <action> 
     <code>1</code> 
     <value>503</value> 
    </action> 
    <action> 
     <code>5</code> 
     <value>87</value> 
    </action> 
    <action> 
     <code>3</code> 
     <value>0</value> 
    </action> 
    <action> 
     <code>5</code> 
     <value>64</value> 
    </action> 
    <action> 
     <code>4</code> 
     <value>0</value> 
    </action> 
    <action> 
     <code>2</code> 
     <value>27</value> 
    </action> 
</result> 
+0

Мартин, могли бы вы объяснить строку '' , потому что я пытаюсь вставить ваше решение в общую таблицу стилей, которую я имею, но я не могу заставить ее работать. Похоже, эта строка не дает никакого вывода. См. Полный исходный XML и XSLT здесь: http://pastebin.com/JC9Gqdgb –

+0

Похоже, проблема возникает из-за пространства имен по умолчанию в документе 'xmlns =" ​​http://www.company.com/log/lk/pl «'. Я не совсем понимаю, почему –

+0

@MarkVeenstra, поскольку ваш XSLT определяет пространство имен по умолчанию для элементов, элементы внутри 'param', которые я установил, также попадают в это пространство имен и таким образом путь' code code-map/code/@ from' не выбирает их. Вам нужно поставить ' ...' на параметр, чтобы избежать этой проблемы. –

0

Только потому, что я сказал, здесь решение xslt-1.0.

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > 
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/> 

    <xsl:template match="action" /> 

    <xsl:template match="action [code = 'co' or code = 'st' or code = 'dec' or code = 'pi' or code = 'del']" > 
     <result> 
      <xsl:copy> 
       <code> 
        <xsl:choose> 
         <xsl:when test="code = 'co'">1</xsl:when> 
         <xsl:when test="code = 'st'">5</xsl:when> 
         <xsl:when test="code = 'dec'">2</xsl:when> 
         <xsl:when test="code = 'pi'">3</xsl:when> 
         <xsl:when test="code = 'del'">4</xsl:when> 
        </xsl:choose> 
       </code> 
      <value> 
       <xsl:variable name="ptr" select="preceding-sibling::action[code='tr'][1]"/> 
       <xsl:variable name="trpos" select="count($ptr/preceding-sibling::action)"/> 
       <xsl:variable name="pcode" select="preceding-sibling::action[code = 'co' or code = 'st' or code = 'dec' or code = 'pi' or code = 'del'][1]"/> 
       <xsl:variable name="codepos" select="count($pcode/preceding-sibling::action)"/> 
       <xsl:choose> 
        <xsl:when test="$trpos >= $codepos"> 
         <xsl:value-of select="round($ptr/value)" /> 
        </xsl:when> 
        <xsl:otherwise>0</xsl:otherwise> 
       </xsl:choose> 

      </value> 
      </xsl:copy> 
     </result> 

    </xsl:template> 
    <xsl:template match="/actions"> 
     <result> 
      <xsl:apply-templates select="action" /> 
     </result> 

    </xsl:template> 
</xsl:stylesheet> 
Смежные вопросы