Простой XSLT шаблон - PullRequest
       0

Простой XSLT шаблон

1 голос
/ 09 февраля 2011

Есть документ XML:

<data>how;many;i;can;tell;you</data>

Необходимо получить XML с использованием XSLT версии 1 :

 <manydata>
     <onedata>how</onedata>
     <onedata>many</onedata>
     <onedata>i</onedata>
     <onedata>can</onedata>
     <onedata>tell</onedata>
     <onedata>you</onedata>
   </manydata>

Как я могу это сделать?

UPDATE: Выходной формат должен быть XML .

Ответы [ 4 ]

1 голос
/ 09 февраля 2011

Это рекурсивное решение, вероятно, одно из самых коротких :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="data">
  <manydata><xsl:apply-templates/></manydata>
 </xsl:template>

 <xsl:template match="text()" name="tokenize">
  <xsl:param name="pText" select="."/>
   <xsl:if test="string-length($pText)">
      <onedata>
       <xsl:value-of select=
        "substring-before(concat($pText,';'),';')"/>
      </onedata>
      <xsl:call-template name="tokenize">
       <xsl:with-param name="pText" select=
        "substring-after($pText,';')"/>
      </xsl:call-template>
     </xsl:if>
 </xsl:template>
</xsl:stylesheet>

когда это преобразование применяется к предоставленному документу XML;

<data>how;many;i;can;tell;you</data>

желаемый, правильный результат получается:

<manydata>
   <onedata>how</onedata>
   <onedata>many</onedata>
   <onedata>i</onedata>
   <onedata>can</onedata>
   <onedata>tell</onedata>
   <onedata>you</onedata>
</manydata>
1 голос
/ 09 февраля 2011
<xsl:template match="data">
    <manydata>
        <!-- 
            empty <manydata/> will be generated,
            if <data/> without child text() 
        -->
        <xsl:apply-templates select="text()"/>
    </manydata>
</xsl:template>

<xsl:template match="data/text()">
    <!-- start point for recursion -->
    <xsl:call-template name="tokenize-string">
        <xsl:with-param name="separator" select="';'"/>
        <xsl:with-param name="string" select="text()"/>
    </xsl:call-template>
</xsl:template>

<xsl:template name="tokenize-string">
    <xsl:param name="separator"/>
    <xsl:param name="string"/>
    <xsl:variable name="string-before-separator" 
        select="substring-before( $string, $separator )"/>
    <onedata>
        <xsl:choose>
            <!-- if $separator presents in $string take first piece -->
            <xsl:when test="$string-before-separator">
                <xsl:value-of select="$string-before-separator"/>
            </xsl:when>
            <!-- take whole $string, if no $separator in the $string -->
            <xsl:otherwise>
                <xsl:value-of select="$string"/>
            </xsl:otherwise>
        </xsl:choose>
    </onedata>
    <!-- recursive call, if separator was found -->
    <xsl:if test="$string-before-separator">
        <xsl:call-template name="tokenize-string">
            <xsl:with-param name="separator" select="$separator"/>
            <xsl:with-param name="string" 
                select="substring-after( $string, $separator )"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>
0 голосов
/ 09 февраля 2011

Вы можете использовать библиотеку расширения XSLT , чтобы получить функцию токенизации. Вот как будет выглядеть окончательный код:

<xsl:template match="/">
 <manydata>
 <xsl:for-each select="str:tokenize(data, ';')">
      <xsl:value-of select="." />
   </xsl:for-each> 
 </manydata>
</xsl:template>
</xsl:stylesheet>

Обратите внимание, что вам придется импортировать библиотеку расширений в ваш XSLT, используя:

<xsl:import href="path/str.xsl" />

перед использованием библиотечных функций.

0 голосов
/ 09 февраля 2011

Попробуйте:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="data">
   <xsl:element name="manydata">
      <xsl:call-template name="splitsemicolons">
        <xsl:with-param name="text" select="text()" />
      </xsl:call-template>
    </xsl:element>
  </xsl:template>

  <xsl:template name="splitsemicolons">
    <xsl:param name="text" />
    <xsl:choose>
      <xsl:when test="contains($text,';')">
        <xsl:element name="onedata">
          <xsl:value-of select="substring-before($text,';')" />
         </xsl:element>
         <xsl:call-template name="splitsemicolons">
           <xsl:with-param name="text" select="substring-after($text,';')" />
         </xsl:call-template>
       </xsl:when>
       <xsl:otherwise>
         <xsl:element name="onedata">
           <xsl:value-of select="$text" />
         </xsl:element>
       </xsl:otherwise>
     </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

При этом используется именованный шаблон, который вызывается рекурсивно, каждый раз выводя то, что находится до первого ;, и вызывая себя со всем после первого ;.Если нет ;, он просто выводит то, что осталось как есть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...