2014-12-02 8 views
0

У меня есть следующий код, если Destination не присутствует, ни терминал, ни внимание не должны отображаться.Как объединить элементы в список, разделенный запятой, с помощью XSLT?

<?xml version="1.0" encoding="utf-8"?> 
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:import href="Request.xsl" /> 
    <xsl:template name="Params"> 
     <xsl:apply-templates select="/Params/Destinations"/> 
    </xsl:template> 
    <xsl:template name="Params"> 
     <xsl:choose> 
      <xsl:when test="string-length($Destinations) &gt; 0"> 
       <xsl:value-of select="$Destinations"/> 
      </xsl:when> 
     </xsl:choose> 
    </xsl:template> 

    <xsl:variable name="Desinations"> 
     <xsl:for-each select="/Params/Destination1/text() | 
          /Params/Destination2/text() | 
          /Params/Destination3/text() | 
          /Params/Destination4/text() | 
          /Params/Destination5/text()"> 
      <xsl:value-of select="."/> 
      <xsl:if test="name(.) = 'Destination1'"> 
       <xsl:apply-templates select="/Params/Terminal1"/> 
       <xsl:apply-templates select="/Params/Attention1"/> 
      </xsl:if> 
       <!-- This xsl:if is repeated 5 more times with Destination2, Destination3, etc. --> 
      <xsl:if test="not(position() = last())"> 
       <xsl:text>,</xsl:text> 
      </xsl:if> 
     </xsl:for-each> 
    </xsl:variable> 

    <xsl:template match="Destination1"> 
     <!-- Covered in the Destinations template --> 
    </xsl:template> 

    <xsl:template match="Terminal1"> 
     <xsl:if test="(. != '')"> 
      <xsl:text>-</xsl:text> 
      <xsl:copy-of select="." /> 
     </xsl:if> 
    </xsl:template> 

    <xsl:template match="Attention1"> 
     <xsl:if test="(. != '')"> 
      <xsl:text>-</xsl:text> 
      <xsl:copy-of select="." /> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 

Я хотел бы иметь возможность получить результат, как так:

Destination1-terminal1, Destination2-Terminal2, Destination3-Terminal3-Attention3

Я получаю следующее результат:

Пункт назначения3, Пункт назначения1, Пункт назначения2-Терминал2-Терминал3-Внимание3

Как вы видите, адресаты не работают, терминал 1 отсутствует, а все остальные элементы терминала и внимания прикреплены к Destination2.

Я не совсем уверен, как объединить элементы Destination-Terminal-Attention вместе и получить запятую после последнего элемента в этом наборе. Например, если Attention не имеет значения, я бы хотел, чтобы запятая появилась после терминала, и если ни у терминалов, ни у Attention нет значений, запятая должна появиться после Destination.

Добавлен источник XML:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text"/> 
    <xsl:include href="../base/Formatting.xsl" /> 

    <xsl:template match="/"> 
     <xsl:text>TO/</xsl:text> 
     <xsl:call-template name="Destinations"/> 
     <xsl:apply-templates select="Params"/> 
    </xsl:template> 

    <xsl:template name="Destinations" /> 

    <xsl:template name="Params"/> 

    <xsl:template match="Params"> 
     <xsl:call-template name="Params"/> 
    </xsl:template> 
</xsl:stylesheet> 

Edit: Я сделал изменения в шаблон Params, просто заходящее Направление. Теперь ни один из полей терминала или внимания не появляется, поэтому, возможно, это шаг назад.

+1

Не могли бы вы опубликовать пример ввода? Также укажите XSLT 1.0 или 2.0. –

+0

Это XSLT 1.0. Я новичок в XSLT, поэтому я не уверен, что вы подразумеваете под примером ввода. Он приходит через форму, где каждый пункт назначения, терминал, внимание - это поле. Назначение - буквенно-цифровое значение длиной 4 символа (ex 1UPD). Терминал представляет собой буквенно-цифровое значение длиной 3 символа (например, US4), а значение - буквенно-цифровое значение длиной 14 символов. Если это не то, что вы ищете, дайте мне знать. Благодаря! – Robert

+1

Вход в XSLT является XML-документом. Нам нужно увидеть (или, желательно, минимизированный, но все еще полный пример), чтобы попытаться воспроизвести вашу проблему. Хотя я нахожусь в этом: минимизация вашего XSLT-кода только для того, что необходимо для воспроизведения проблемы **, и ** сделать это завершено также будет полезно. –

ответ

0

В XPath, | действительно представляет собой операцию объединения и не гарантирует какого-либо конкретного заказа результатов. Вы можете обеспечить проверку порядка документа путем добавления явного <xsl:sort> к вашему циклу for-each. How to do an XSL:for-each in reverse order показывает, как сканировать назад через результирующий набор; изменение «нисходящего» на «восходящее» должно делать то, что вы хотите.

Или вы можете избавиться от xsl:for-each и заменить его на xsl:apply-templates, перемещая тело каждого из них в подходящий шаблон. Применить операцию processes the selected nodes in document order unless overridden by an <xsl:sort>.

Вообще, если вы считаете, что вам нужно xsl:for-each вероятно, вы должны смотреть на xsl:apply-templates вместо (возможно, с mode), если вы специально не хотите детально контролировать порядок результатов. XSLT является непроцедурным языком и лучше всего работает, если вы используете его таким образом - «обрабатывайте эти», а не «перебирайте их».

+0

Информация о "//" неверна. Все выражения путей (и выражения объединения) доставляют результаты в порядке документа, и это применимо как к шаблонам применений, так и к каждому. Кроме того, причины спецификации не являются «историческими»: WG, которые определили правила, имели совершенно свободную руку, и они выбрали этот проект по техническим причинам. –

+1

@MichaelKay: Исправьте меня, если я ошибаюсь, но, строго говоря, я считаю, что есть исключения из этого правила: previous-sibling :: *, previous :: *, ancestor :: * и ancestor-or-self :: * return узлы в обратном порядке, т. е. previous-sibling :: * [1] вернут непосредственно предшествующий-братьев, а не первый родной брат в порядке документа. (previous-sibling :: *) [1] вернул бы первое в соответствии с порядком документа. – Flynn1179

+0

@MichaelKay: Я поцарапаю этот параграф до проверки работоспособности; Я был вне XSLT-реализации в течение двух лет ... но я никогда не слышал надежной защиты дополнительной сложности //, и был бы признателен за указатель на один. – keshlam

0

Я смог разобраться с этим, используя некоторые советы, предлагаемые кешлам. В моем случае у меня не было доступа к XML-вводу, о котором спрашивал другой пользователь. Я думаю, что это сгенерировано программно в приложении. Мое решение может быть мерзостью для XSLT, но с учетом моих ограничений оно работает.

Я изменил XSL: переменная Направления немного:

<xsl:variable name="Destinations"> 
    <xsl:for-each select="/StatelinkQuery/Arguments/Destination1 | 
          /StatelinkQuery/Arguments/Destination2 | 
          /StatelinkQuery/Arguments/Destination3 | 
          /StatelinkQuery/Arguments/Destination4 | 
          /StatelinkQuery/Arguments/Destination5"> 
     <xsl:sort select="name()" order="ascending"/> 
     <xsl:apply-templates select="."/> 
     <xsl:if test="not(position() = last())"> 
      <xsl:text>,</xsl:text> 
     </xsl:if> 
    </xsl:for-each> 
</xsl:variable> 

Шаблон для каждого назначения был изменен следующим образом:

<xsl:template match="Destination1"> 
    <xsl:value-of select="." /> 
    <xsl:apply-templates select="/StatelinkQuery/Arguments/Terminal1"/> 
    <xsl:apply-templates select="/StatelinkQuery/Arguments/Attention1"/> 
</xsl:template> 
Смежные вопросы