XSLT взять строку за строкой из текста какого-либо элемента - PullRequest
2 голосов
/ 25 февраля 2012

Я хотел бы спросить, есть ли какой-нибудь способ в XSLT взять строку за строкой в ​​каком-либо элементе и применить что-то к этой строке. Например, у меня есть

<screen>
Volume in drive C is SYSTEM         Serial number is 2350:717C    
Directory of  C:\

10/17/97   9:04         &lt;DIR&gt;    bin
10/16/97  14:11         &lt;DIR&gt;    DOS
10/16/97  14:40         &lt;DIR&gt;    Program Files
10/16/97  14:46         &lt;DIR&gt;    TEMP
10/17/97   9:04         &lt;DIR&gt;    tmp
10/16/97  14:37         &lt;DIR&gt;    WINNT
10/16/97  14:25             119  AUTOEXEC.BAT
2/13/94   6:21          54,619  COMMAND.COM
10/16/97  14:25             115  CONFIG.SYS
11/16/97  17:17      61,865,984  pagefile.sys
2/13/94   6:21           9,349  WINA20.386
</screen>

и я хотел бы взять строку за строкой и ставить пробел (скобка, дефис и т. Д.) Перед каждой строкой.

Спасибо за любую помощь: -)

Ответы [ 2 ]

4 голосов
/ 25 февраля 2012

I. Решение XSLT 2.0:

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

 <xsl:template match="/*">
  <screen>
   <xsl:for-each select="tokenize(., '\r?\n')">
    line: <xsl:sequence select="."/>
   </xsl:for-each>
  </screen>
 </xsl:template>
</xsl:stylesheet>

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

<screen>
    Volume in drive C is SYSTEM         Serial number is 2350:717C
    Directory of  C:\

    10/17/97   9:04         &lt;DIR&gt;    bin
    10/16/97  14:11         &lt;DIR&gt;    DOS
    10/16/97  14:40         &lt;DIR&gt;    Program Files
    10/16/97  14:46         &lt;DIR&gt;    TEMP
    10/17/97   9:04         &lt;DIR&gt;    tmp
    10/16/97  14:37         &lt;DIR&gt;    WINNT
    10/16/97  14:25             119  AUTOEXEC.BAT
    2/13/94   6:21          54,619  COMMAND.COM
    10/16/97  14:25             115  CONFIG.SYS
    11/16/97  17:17      61,865,984  pagefile.sys
    2/13/94   6:21           9,349  WINA20.386
</screen>

желаемый, правильный результат (перед каждой строкой текстового узла стоит строка "line: ") получается :

<screen>
    line: 
    line:     Volume in drive C is SYSTEM         Serial number is 2350:717C
    line:     Directory of  C:\
    line: 
    line:     10/17/97   9:04         &lt;DIR&gt;    bin
    line:     10/16/97  14:11         &lt;DIR&gt;    DOS
    line:     10/16/97  14:40         &lt;DIR&gt;    Program Files
    line:     10/16/97  14:46         &lt;DIR&gt;    TEMP
    line:     10/17/97   9:04         &lt;DIR&gt;    tmp
    line:     10/16/97  14:37         &lt;DIR&gt;    WINNT
    line:     10/16/97  14:25             119  AUTOEXEC.BAT
    line:     2/13/94   6:21          54,619  COMMAND.COM
    line:     10/16/97  14:25             115  CONFIG.SYS
    line:     11/16/97  17:17      61,865,984  pagefile.sys
    line:     2/13/94   6:21           9,349  WINA20.386
    line: </screen>

Объяснение

Надлежащее использование функции tokenize() со вторым аргументом RegEx, который позволяет необязательному CR предшествовать символу NL.


II. Решение XSLT 1.0 :

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

 <xsl:template match="text()" name="lines">
  <xsl:param name="pText" select="."/>

  <xsl:if test="string-length($pText)">
   line: <xsl:text/>

   <xsl:value-of select=
   "substring-before(concat($pText, '&#xA;'), '&#xA;')"/>

   <xsl:call-template name="lines">
    <xsl:with-param name="pText" select=
     "substring-after($pText, '&#xA;')"/>
   </xsl:call-template>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

Когда это преобразование XSLT 1.0 применяется к тому же XML-документу (см. Выше), будет получен требуемый результат (каждая строка текстового узла с добавлением строки "line: "):

   line: 
   line:     Volume in drive C is SYSTEM         Serial number is 2350:717C
   line:     Directory of  C:\
   line: 
   line:     10/17/97   9:04         &lt;DIR&gt;    bin
   line:     10/16/97  14:11         &lt;DIR&gt;    DOS
   line:     10/16/97  14:40         &lt;DIR&gt;    Program Files
   line:     10/16/97  14:46         &lt;DIR&gt;    TEMP
   line:     10/17/97   9:04         &lt;DIR&gt;    tmp
   line:     10/16/97  14:37         &lt;DIR&gt;    WINNT
   line:     10/16/97  14:25             119  AUTOEXEC.BAT
   line:     2/13/94   6:21          54,619  COMMAND.COM
   line:     10/16/97  14:25             115  CONFIG.SYS
   line:     11/16/97  17:17      61,865,984  pagefile.sys
   line:     2/13/94   6:21           9,349  WINA20.386

Объяснение

  1. Рекурсивный именованный шаблон для извлечения и вывода каждой следующей строки. Условие остановки - когда строка имеет нулевую длину.

  2. Надлежащее использование substring-before(), substring-after() и сторожевой техники для минимизации длины и сложности кода.

4 голосов
/ 25 февраля 2012

Хорошо с XSLT 2.0, поддерживаемым инструментами Saxon 9 или AltovaXML и другими, вы можете использовать функцию tokenize, например,

<xsl:template match="screen">
  <xsl:for-each select="tokenize(., '\n')">
    <xsl:value-of select="concat('-', .)"/>
  </xsl:for-each>
</xsl:template>

С XSLT 1.0 вы можете проверить, поддерживает ли ваш процессор функцию расширения, такую ​​как http://www.exslt.org/str/functions/tokenize/index.html.

...