Склеивание строк с разделителями в XSL

У меня есть следующая структура, в которой я хочу выловить наиболее релевантные данные и склеить их вместе, чтобы сделать заголовок.

<faults>
  <fault componentName="comp1">
    <introduceWhen>Time1</introduceWhen>
    <signals>
      <signal name="sig11" value="1"/>
      <signal name="sig22" value="1"/>
    </signals>
  </fault>
  <fault componentName="comp2">
    <introduceWhen>Time2</introduceWhen>
    <signals>
      <signal name="sig44" value="0"/>
    </signals>
  </fault>
</faults>

Я бы хотел, чтобы это было comp1 1 1 comp2 0, но пока лучшее, что мне удалось, это comp1 1 1comp2 0, используя это:

<xsl:template match="faults">
  <xsl:for-each select="fault">
    <xsl:variable name="compName" select="@componentName"/>
    <xsl:variable name="sigVals" select="string-join(signals/signal/@value, ' ')"/>
    <xsl:value-of select="concat(@compName, ' ', $sigVals)"/>
  </xsl:for-each>
</xsl:template>

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


person Fylke    schedule 24.09.2016    source источник


Ответы (2)


Поскольку вы, кажется, используете XSLT 2.0, вы можете сделать это просто:

<xsl:template match="/faults">
    <xsl:for-each select="fault">
        <xsl:value-of select="@componentName, signals/signal/@value"/>
        <xsl:text> </xsl:text>
    </xsl:for-each>
</xsl:template>

Или, если вы хотите быть более дотошным:

<xsl:template match="/faults">
    <xsl:for-each select="fault">
        <xsl:value-of select="@componentName, signals/signal/@value"/>
        <xsl:if test="position()!=last()">
            <xsl:text> </xsl:text>
        </xsl:if>
    </xsl:for-each>
</xsl:template>

Или (с намеком на ответ Майкла Кея) еще проще:

<xsl:template match="/faults">
    <xsl:value-of select="fault/@componentName | fault/signals/signal/@value"/>
</xsl:template>

Инструкция xsl:value-of уже вставляет разделитель между отдельными значениями; нет необходимости использовать string-join().

person michael.hor257k    schedule 24.09.2016
comment
Второй работает отлично, мне нужно прочитать об операторе трубы! - person Fylke; 25.09.2016

Разве это не просто

string-join((//@componentName | //@value), ' ')

?

person Michael Kay    schedule 24.09.2016
comment
Вау здорово! Не знал о операторе трубы, должен прочитать об этом. Эта // вещь на самом деле не работает, так как есть и другие части полного XML-файла, в которых есть элементы, называемые сигналами (извините, что не указали это). - person Fylke; 25.09.2016