XSLT: разделение строки и выполнение чего-либо с каждым символом

#xml #xslt

#xml #xslt

Вопрос:

Я новичок в XSLT. Я просмотрел учебные пособия, и мне удалось выполнить около 80% того, что я хотел, с моим XML-документом. Однако я кое на чем застрял. В моем XML-документе у меня есть атрибуты, которые состоят из таких значений, как «ERA», «EDA», «EDAR» и так далее. По сути, эти атрибуты состоят из комбинаций букв E, D, A и R. E, D, A и R сопоставляются для редактирования, удаления, добавления и чтения.

Если бы я делал это в обязательном порядке, я бы разделил строку на составляющие ее символы, а затем проверил каждый символ, чтобы увидеть, следует ли мне выводить, Редактировать, удалять, добавлять или читать. Как я могу сделать что-то подобное в XSLT? Я думал об использовании функций длины и подстроки и создании какого-то цикла.

Ответ №1:

Встроенная (или внешняя) карта:

 <xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:local="http://localhost">
    <local:map letter="E" text="Edit"/>
    <local:map letter="D" text="Delete"/>
    <local:map letter="A" text="Add"/>
    <local:map letter="R" text="Read"/>
    <xsl:template match="test">
        <xsl:copy>
            <xsl:apply-templates
             select="document('')/*/local:map[
                        contains(current(),@letter)
                     ]/@text"
             mode="sequence"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="node()|@*" mode="sequence">
        <xsl:value-of select="concat(substring(' ', 1 div (position()!=1)),.)"/>
    </xsl:template>
</xsl:stylesheet>
  

Вывод:

 <test>Edit Delete Add Read</test>
  

Последовательность xsl:if инструкций:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="test">
        <xsl:copy>
            <xsl:if test="contains(.,'E')">Edit </xsl:if>
            <xsl:if test="contains(.,'D')">Delete </xsl:if>
            <xsl:if test="contains(.,'A')">Add </xsl:if>
            <xsl:if test="contains(.,'R')">Read </xsl:if>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
  

Вывод:

 <test>Edit Delete Add Read </test>
  

Ответ №2:

Предполагая, что атрибут содержит только E D A и R (или вас не волнуют другие возможные значения), простой набор contains(@attr,...) в <xsl:choose...> должен работать нормально:

 <xsl:choose>
  <xsl:when test="contains(@attr,'A')">
    ...
  </xsl:when>
  <xsl:when test="contains(@attr,'D')">
    ...
  </xsl:when>
  etc...
</xsl:choose>
  

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

1. Да, он будет содержать только E, D, A, R. Это кажется намного более простым методом!

2. @Alejandro, будет ли он тестировать ее с каждым <xsl:when> ? Или это выходит за рамки <xsl:choose> , когда одно из предложений совпадает?

Ответ №3:

Я смог решить эту проблему, используя рекурсивную функцию / шаблон:

 <xsl:template name="translateAccessModes">

 <xsl:param name="accessModes" />

 <xsl:if test="string-length($accessModes) > 0">

  <xsl:variable name="accessMode" select="substring($accessModes, 1, 1)" />
  <xsl:choose>
   <xsl:when test="$accessMode='E'">Edit </xsl:when>
   <xsl:when test="$accessMode='D'">Delete </xsl:when>
   <xsl:when test="$accessMode='A'">Add </xsl:when>
   <xsl:when test="$accessMode='R'">Read </xsl:when>
   <xsl:otherwise>Unrecognized Access Mode: <xsl:value-of select="$accessMode" /> </xsl:otherwise>
  </xsl:choose>

  <xsl:call-template name="translateAccessModes">
   <xsl:with-param name="accessModes" select="substring($accessModes, 2, string-length($accessModes))" />
  </xsl:call-template>

 </xsl:if>

</xsl:template>
  

Однако не уверен, что это лучший способ сделать это.