Использование position для подсчета узлов — иногда перечисление начинается с 0 вместо 1

#xml #xslt

#xml #xslt

Вопрос:

Привет, ребята, у меня есть этот довольно неуклюжий фрагмент xslt, который я использую для преобразования тестовых примеров SOAPUI в более читаемый формат. В настоящее время он перечисляет тестовые примеры, используя следующее

<xsl:value-of select="position()-3"/>

Мой вопрос Иногда перечисление тестовых примеров начинается с 0, а иногда с 1. Я не понимаю, почему это происходит? Это как-то связано с тем, как реализован селектор позиции? Есть ли более аккуратный способ подсчета экземпляров узла?

Большое спасибо,

Ричард

Вот код целиком — без оформления.

`

   <!-- Edited by XMLSpy® -->
  <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:con="http://eviware.com/soapui/config">
    <xsl:output method="html" encoding ="utf-8"/>
    <xsl:template match="/">
      <html>
        <head>
          <script type="text/javascript">
            function toggleDiv(divid){
                var ele = document.getElementById(divid);

                if(ele.style.display == 'none')
                    { 
                        ele.style.display = 'block';
                    }
                else
                    {
                        ele.style.display = 'none';
                    }
                }
          </script>  

            <style type="text/css"></style>

        </head>

        <body>

          <xsl:apply-templates/>

          <div class="help">This report is generated automatically by a scheduled job running on Richard Fortune's machine. The SOAPUI project files it references are located in sourcecontrol SVN (https://svn.xxx.xxxxxx.com/svn/network/TEST). These reports are generated daily as the projects they reference are subject to change.</div>

        </body>
      </html>

    </xsl:template>

    <xsl:template match="con:soapui-project">
     <div><h1>Project Name : <xsl:value-of select="@name"/></h1></div> 
      <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="con:testSuite">    

    <xsl:if test="con:description=''">
                <p class="warn"> (RICHARD - PLEASE PROVIDE A DESCRIPTION!!)</p>
    </xsl:if>       
      <div id="content" onmousedown="toggleDiv('{position()}');"><h2 class="ex">TestSuite:  <xsl:value-of select="@name"/></h2></div>
      <br>
        <p class="descSuite"><b>Suite Description: </b><xsl:value-of select="con:description"/></p>
      </br>

      <div style="display:none" id="{position()}"><xsl:apply-templates />
      </div>
    </xsl:template>


    <xsl:template match="con:testCase">

        <ul>
          <li class="tc"><b>
            (#<xsl:value-of select="position()-3"/>) Testcase: </b><xsl:value-of select="@name"/>
          </li>

          <xsl:if test="con:description=''">
            <p class="warn">(Gentle reminder Richard - PLEASE PROVIDE A DESCRIPTION!!)</p>
          </xsl:if>

          <p class="descTc">
            <strong><i>Description:</i></strong> <xsl:value-of select="con:description"/>
          </p>
          <ol class="step">
          <xsl:for-each select="con:testStep"><li>TestStep: <xsl:value-of select="@name"/> </li></xsl:for-each>
          </ol>

        </ul>
        <xsl:apply-templates />

    </xsl:template>


    <xsl:template match="*"></xsl:template>


  </xsl:stylesheet>
  

`

Комментарии:

1. Было бы полезно иметь образец вашего ввода XML.

2. Пожалуйста, отредактируйте свой вопрос и предоставьте полный (но как можно более короткий) XML-документ. Также укажите неверный результат, который вы получаете, и объясните, каким должен быть правильный результат. Я думаю, что знаю, в чем может быть проблема, но я не хочу тратить время на догадки.

Ответ №1:

Я предлагаю вам использовать count() :

 <xsl:value-of select="count(preceding-sibling::*) 1"/>
  

Это возвращает текущее положение узла относительно всех его родственных элементов (на основе 1).

position() может быть неправильным способом в зависимости от контекста.

Комментарии:

1. ‘Это возвращает текущее положение узла относительно всех его родственных элементов (на основе 1).’ — фактически по отношению ко всем его предыдущим родственным элементам неродственным. Это критическое различие, потому что проблема, с которой сталкивается OP position() , заключается в том, что он подсчитывает все предыдущие узлы-братья, включая те, которые не являются элементами, такие как текстовые узлы с пробелами.

2. да, именно поэтому count так лучше. Предоставленный мною XPath будет учитывать только предыдущие родственные элементы. Что тогда ищет OP?

3. Я полагаю, что вы правы относительно того, что ищет OP, и ваш XPath поступает правильно. Я просто указывал на то, что ваше описание «[с] учетом всех его родственных элементов » вводит в заблуждение; я полагаю, вы имели в виду «[с] учетом всех его родственных текстовых узлов, комментариев и т.д.» (т. Е. исключая родственные текстовые узлы, комментарии и т.д.).

4. Привет, Empo, я также попробовал пример, который вы привели выше. Мне пришлось немного изменить его, чтобы откалибровать количество. Я использовал предоставленный LarsH образец, учитывая, что он сразу же сработал для меня. Однако я предпочитаю точность подхода, который вы предлагаете, и сохраню это в своем наборе трюков для дальнейшего использования! Спасибо за ваш ответ!

5. 1, поскольку вы исправили предложение (и в первую очередь предоставили рабочее решение). count() безусловно, имеет некоторые преимущества перед <xsl:number> , особенно прозрачность: вам не нужно много знать о поведении по умолчанию, чтобы иметь возможность предсказать, что это будет делать.

Ответ №2:

Вот как вы могли бы использовать <xsl:number> , что более эффективно, чем использование count() :

 <li class="tc">
  <b>(#<xsl:number/>) Testcase: </b><xsl:value-of select="@name"/>
</li>
  

Это так просто! По умолчанию <xsl:number> подсчитываются узлы того же типа узла (в данном случае элементы) и с тем же именем элемента, что и контекстный узел … я полагаю, это то, что вы здесь хотите. Таким образом, он будет подсчитывать <con:testCase> элементы.

Комментарии:

1. Привет, Ларс, я попробовал это первым, и это отлично сработало «из коробки». Спасибо за это!

Ответ №3:

Проблема с position() в том, что он может (и часто включает) включать узлы, которые вы не ожидаете, такие как текстовые или даже пробельные узлы, если кто-либо прочитал XML, сохранил его.

В зависимости от ваших точных требований, вы можете посчитать количество предыдущих родственных элементов (как описано @empo), или, возможно, стоит заглянуть в <xsl:number> инструкцию.

Комментарии:

1.Хорошие моменты; но использование терминов неверно и сбивает с толку: вопреки тому, что подразумевает ваш ответ, термин «элементы» не включает текстовые или пробельные узлы; тогда как текстовые узлы действительно включают пробельные узлы.

2. 1 за предложение <xsl:number> , которое обычно намного эффективнее, чем count() . -1 за неправильную терминологию.

3. Да, верно. Я виню .NET, я слишком привык использовать SelectSingleNode при поиске элементов; Я знаю, что он, конечно, может возвращать и другие узлы, но у меня появилась дурная привычка думать об узлах / элементах как об одном и том же. От старых привычек трудно избавиться. Я изменю ответ.