#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
при поиске элементов; Я знаю, что он, конечно, может возвращать и другие узлы, но у меня появилась дурная привычка думать об узлах / элементах как об одном и том же. От старых привычек трудно избавиться. Я изменю ответ.