Создание новых элементов с помощью обработки текста в XSLT - PullRequest
1 голос
/ 13 июля 2010

Мне интересно, можно ли / как выполнить следующее в XSLT.Если нет, что бы вы использовали?(Я использовал OmniMark, но я хотел бы знать, возможно ли это в XSLT.)

Вот пример входного XML:

<?xml version="1.0" encoding="UTF-8"?>
<fragment>
    <firstElem>
        <secondElem>D12</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>A3J7-10</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>C2-4</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>QW9R7NP20-25</secondElem>
    </firstElem>
</fragment>

Мне нужно было взятьтекстовое содержимое элемента secondElem и создайте столько новых элементов firstElem, сколько необходимо.«-» было «сквозным», поэтому «A3J7-10» на самом деле было «от A3J7» до «A3J10» (A3J7, A3J8, A3J9, A3J10).(Иногда «сквозной» может быть довольно большим, как A1B2C1-150 (A1B2C1 до A1B2C150).)

Если бы не было тире, ничего не нужно было делать.выходной XML:

<?xml version="1.0" encoding="UTF-8"?>
<fragment>
    <firstElem>
        <secondElem>D12</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>A3J7</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>A3J8</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>A3J9</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>A3J10</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>C2</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>C3</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>C4</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>QW9R7NP20</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>QW9R7NP21</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>QW9R7NP22</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>QW9R7NP23</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>QW9R7NP24</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>QW9R7NP25</secondElem>
    </firstElem>
</fragment>

Есть ли способ сделать это в XSLT?

Спасибо!

Ответы [ 2 ]

2 голосов
/ 13 июля 2010

Эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xsl">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="firstElem[contains(.,'-')]" name="firstElem">
        <xsl:param name="from">
            <xsl:call-template name="getfrom"/>
        </xsl:param>
        <xsl:param name="base" select="normalize-space(substring-before(.,concat($from,'-')))"/>
        <xsl:param name="to" select="substring-after(.,'-')"/>
        <xsl:if test="$to >= $from">
            <firstElem>
                <secondElem>
                    <xsl:value-of select="concat($base,$from)"/>
                </secondElem>
            </firstElem>
            <xsl:call-template name="firstElem">
                <xsl:with-param name="from" select="$from + 1"/>
                <xsl:with-param name="base" select="$base"/>
                <xsl:with-param name="to" select="$to"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
    <xsl:template name="getfrom">
        <xsl:param name="string" select="substring-before(.,'-')"/>
        <xsl:variable name="last" select="substring($string,string-length($string))"/>
        <xsl:if test="contains('0123456789',$last)">
            <xsl:call-template name="getfrom">
                <xsl:with-param name="string" select="substring($string,1,string-length($string)-1)"/>
            </xsl:call-template>
            <xsl:value-of select="$last"/>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

Выход:

<fragment>
    <firstElem>
        <secondElem>D12</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>A3J7</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>A3J8</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>A3J9</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>A3J10</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>C2</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>C3</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>C4</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>QW9R7NP20</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>QW9R7NP21</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>QW9R7NP22</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>QW9R7NP23</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>QW9R7NP24</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>QW9R7NP25</secondElem>
    </firstElem>
</fragment>
1 голос
/ 13 июля 2010

Вот решение XSLT 2.0 :

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="firstElem[contains(secondElem, '-')]">
   <xsl:analyze-string select="secondElem"
    regex="(^.*[^\d])([\d]*)-([\d]*)">

     <xsl:matching-substring>
        <xsl:variable name="vbaseName" select="regex-group(1)"/>
        <xsl:variable name="vstart" select="regex-group(2)"/>
        <xsl:variable name="vend" select="regex-group(3)"/>

        <xsl:for-each select=
          "xs:integer($vstart) to xs:integer($vend)">
                <firstElem>
                    <secondElem>
                      <xsl:value-of select="concat($vbaseName, .)"/>
                    </secondElem>
                </firstElem>
        </xsl:for-each>
     </xsl:matching-substring>
   </xsl:analyze-string>
 </xsl:template>
</xsl:stylesheet>

Когда вышеуказанное преобразование применяется к предоставленному документу XML :

<fragment>
    <firstElem>
        <secondElem>D12</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>A3J7-10</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>C2-4</secondElem>
    </firstElem>
    <firstElem>
        <secondElem>QW9R7NP20-25</secondElem>
    </firstElem>
</fragment>

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

<fragment>
    <firstElem>
        <secondElem>D12</secondElem>
    </firstElem>
    <firstElem>
      <secondElem>A3J7</secondElem>
   </firstElem>
   <firstElem>
      <secondElem>A3J8</secondElem>
   </firstElem>
   <firstElem>
      <secondElem>A3J9</secondElem>
   </firstElem>
   <firstElem>
      <secondElem>A3J10</secondElem>
   </firstElem>
    <firstElem>
      <secondElem>C2</secondElem>
   </firstElem>
   <firstElem>
      <secondElem>C3</secondElem>
   </firstElem>
   <firstElem>
      <secondElem>C4</secondElem>
   </firstElem>
    <firstElem>
      <secondElem>QW9R7NP20</secondElem>
   </firstElem>
   <firstElem>
      <secondElem>QW9R7NP21</secondElem>
   </firstElem>
   <firstElem>
      <secondElem>QW9R7NP22</secondElem>
   </firstElem>
   <firstElem>
      <secondElem>QW9R7NP23</secondElem>
   </firstElem>
   <firstElem>
      <secondElem>QW9R7NP24</secondElem>
   </firstElem>
   <firstElem>
      <secondElem>QW9R7NP25</secondElem>
   </firstElem>
</fragment>

Do note :

  1. Использование обычноговыражения.

  2. Захват подвыражения и функция regex-group().

  3. Использование <xsl:analyze-string> и <xsl:matching-substring>.

  4. Использование оператора to для создания последовательности, которая будет использоваться в <xsl:for-each>

  5. Использование <xsl:for-each> в последовательностине узлов (целых).

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