是否可以在XSLT:中解析这种文本
Détail|Numéro appelé|Date et heure|Quantitéréelle|Qantitéfacturée|H.T.|T.T.C。上诉人不可移动|0611XXXXXX|14/06-09h32|00h00mn23s|00h00n23s|小费|小费上诉人不可携带|0688XXXXXX|14/06-10h39|00h01mn16s|00h01 mn16s|小费|小费上诉人不可移动|0611XXXXXX|18/06-07h24|00h00mn50s|00h00n50s|小费|小费上诉人不可移动|0688XXXXXX|20/06-09h32|00h00mn23s|00h00n23s|小费|小费上诉人不可携带|0688XXXXXX|20/06-10h44|00h01mn27s|00h01 mn27s|小费|小费上诉人不可移动|0611XXXXXX|25/06-21h09|00h00mn22s|00h00n22s|feet|feet上诉人不可移动|0626XXXXX|29/06-11h25|00h00mn27s|00h00n27s|小费|小费Appel vers un-portable |0688XXXXXX|02/07-13h39|00h02mn37s|00h02 mn37s| tiunt|tiunt
此表是变量中的内容,我想用</td><td>
(如果可能的话,第一行可能是<th>
)替换"|"字符,并添加<tr>
。
而且。。。使用XSLT1.0执行此操作。
非常感谢。
正如其他人所说,这绝对不是XSLT的工作——然而,只是为了好玩,它可以使用XSLT1.0来完成。这是使用XMLSpy进行测试的,因此可能需要使用exslt将结果树片段转换为节点集。但原则是一样的。对于技术解决方案,请跳过接下来的几段
编辑(根据问题中的评论):我没有足够的代表在正确的地方发表评论,然而,这个问题是一个完美的例子,说明了技术解决方案是不够的。
您曾说过,在使用XSLT方面"别无选择",但我认为这突出了我在许多IT专业人员身上看到的一个问题。您可能无法选择当前工作环境的状态(我认为这是一个工作解决方案,因为没有一个思维正确的教育者会将其作为如何使用XSLT的示例)。您可以选择的是如何将此解决方案交付给任何提出要求的人。
这个问题的真正解决方案是XSLT肯定不是解决这个问题的正确方法,而这正是你的雇主或客户需要知道的。虽然我下面的解决方案是解决您问题的非常有效的方法,但我认为这不是最佳实践,不是XSLT的适当使用,也不是解决此问题的最有效方法,而且在专业环境中,您有责任说同样的话。
人们可能不喜欢被告知他们的环境是错误的,或者他们希望如何解决某件事并不是应该如何解决,但如果他们来找你寻求建议,那么你的建议应该包括适当的标准。因此,无论如何,请提出下面的解决方案,但一定要提出上面的论点——这样,即使他们在XSLT中实现了它,至少你已经尽到了告知和教育的职责,如果最终使用了一个糟糕的解决方案时,批评被记录下来,那么如果它失败了,你就没有责任了。
实际的XSLT解决方案从这里开始:
输入(请注意,您需要在代码周围添加一个标签,使其成为有效的XML):
<text>Détail|Numéro appelé|Date et heure|Quantité réelle|Qantité facturée|H.T.|T.T.C.
Appel vers un portable|06110XXXXX|14/06 - 09h32|00h00mn23s|00h00mn23s|gratuit|gratuit
Appel vers un portable|06889XXXXX|14/06 - 10h39|00h01mn16s|00h01mn16s|gratuit|gratuit
Appel vers un portable|06110XXXXX|18/06 - 07h24|00h00mn50s|00h00mn50s|gratuit|gratuit
Appel vers un portable|06889XXXXX|20/06 - 09h32|00h00mn23s|00h00mn23s|gratuit|gratuit
Appel vers un portable|06889XXXXX|20/06 - 10h44|00h01mn27s|00h01mn27s|gratuit|gratuit
Appel vers un portable|06110XXXXX|25/06 - 21h09|00h00mn22s|00h0n0mn22s|gratuit|gratuit
Appel vers un portable|06267XXXXX|29/06 - 11h25|00h00mn27s|00h00mn27s|gratuit|gratuit
Appel vers un portable|06889XXXXX|02/07 - 13h39|00h02mn37s|00h02mn37s|gratuit|gratuit
Appel vers un portable|06889XXXXX|02/07 - 18h17|00h06mn55s|00h06mn55s|gratuit|gratuit
Appel vers un portable|06110XXXXX|05/07 - 19h29|00h00mn15s|00h00mn15s|gratuit|gratuit</text>
XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="lines">
<xsl:call-template name="tokenize">
<xsl:with-param name="string">
<xsl:value-of select="."/>
</xsl:with-param>
<xsl:with-param name="token">
<xsl:value-of select="' '"/>
</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<table>
<xsl:for-each select="$lines/match">
<xsl:variable name="cells">
<xsl:call-template name="tokenize">
<xsl:with-param name="string">
<xsl:value-of select="."/>
</xsl:with-param>
<xsl:with-param name="token">
<xsl:value-of select="'|'"/>
</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<tr>
<xsl:for-each select="$cells/match">
<td><xsl:value-of select="."/></td>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
</xsl:template>
<!--
Tokenize with a string and token allows us to split up string on a given token and return a node-set of all of the separate components in <match> tags.
Taken from: http://stackoverflow.com/a/141022/764357
Then modified to use a generic split token.
-->
<xsl:template name="tokenize">
<xsl:param name="string"/>
<xsl:param name="token" select="','"/>
<xsl:param name="count" select="0"/>
<xsl:variable name="first_elem" select="substring-before(concat($string,$token), $token)"/>
<!-- Make sure at least one token at the end exists -->
<xsl:variable name="remaining" select="substring-after($string, $token)"/>
<match>
<xsl:value-of select="$first_elem"/>
</match>
<!--
We check that the remaining list is not just a single token, if it is then the recursive base case has been identified.
-->
<xsl:if test="$remaining and $remaining != $token">
<xsl:call-template name="tokenize">
<xsl:with-param name="string" select="$remaining"/>
<xsl:with-param name="token" select="$token"/>
<xsl:with-param name="count" select="$count + 1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
输出:
<table>
<tr>
<td>Détail</td>
<td>Numéro appelé</td>
<td>Date et heure</td>
<td>Quantité réelle</td>
<td>Qantité facturée</td>
<td>H.T.</td>
<td>T.T.C.</td>
</tr>
<tr>
<td>Appel vers un portable</td>
<td>06110XXXXX</td>
<td>14/06 - 09h32</td>
<td>00h00mn23s</td>
<td>00h00mn23s</td>
<td>gratuit</td>
<td>gratuit</td>
</tr>
<tr>
<td>Appel vers un portable</td>
<td>06889XXXXX</td>
<td>14/06 - 10h39</td>
<td>00h01mn16s</td>
<td>00h01mn16s</td>
<td>gratuit</td>
<td>gratuit</td>
</tr>
<tr>
<td>Appel vers un portable</td>
<td>06110XXXXX</td>
<td>18/06 - 07h24</td>
<td>00h00mn50s</td>
<td>00h00mn50s</td>
<td>gratuit</td>
<td>gratuit</td>
</tr>
<tr>
<td>Appel vers un portable</td>
<td>06889XXXXX</td>
<td>20/06 - 09h32</td>
<td>00h00mn23s</td>
<td>00h00mn23s</td>
<td>gratuit</td>
<td>gratuit</td>
</tr>
<tr>
<td>Appel vers un portable</td>
<td>06889XXXXX</td>
<td>20/06 - 10h44</td>
<td>00h01mn27s</td>
<td>00h01mn27s</td>
<td>gratuit</td>
<td>gratuit</td>
</tr>
<tr>
<td>Appel vers un portable</td>
<td>06110XXXXX</td>
<td>25/06 - 21h09</td>
<td>00h00mn22s</td>
<td>00h0n0mn22s</td>
<td>gratuit</td>
<td>gratuit</td>
</tr>
<tr>
<td>Appel vers un portable</td>
<td>06267XXXXX</td>
<td>29/06 - 11h25</td>
<td>00h00mn27s</td>
<td>00h00mn27s</td>
<td>gratuit</td>
<td>gratuit</td>
</tr>
<tr>
<td>Appel vers un portable</td>
<td>06889XXXXX</td>
<td>02/07 - 13h39</td>
<td>00h02mn37s</td>
<td>00h02mn37s</td>
<td>gratuit</td>
<td>gratuit</td>
</tr>
<tr>
<td>Appel vers un portable</td>
<td>06889XXXXX</td>
<td>02/07 - 18h17</td>
<td>00h06mn55s</td>
<td>00h06mn55s</td>
<td>gratuit</td>
<td>gratuit</td>
</tr>
<tr>
<td>Appel vers un portable</td>
<td>06110XXXXX</td>
<td>05/07 - 19h29</td>
<td>00h00mn15s</td>
<td>00h00mn15s</td>
<td>gratuit</td>
<td>gratuit</td>
</tr>
</table>
如果不使用扩展,将会很痛苦,您将不得不将其作为外部参数传递或放入一些标记中。Xslt是关于转换Xml文件而不是文本文件的,所以请使用正确的工具来完成任务。
使用XSLT2.0的regex功能解析这样的输入要容易得多。
但是,如果每行只需要一个tr
,每个竖条上有一个td
边界,那么可以使用两个命名模板(或一个更复杂的模板)方便地做到这一点:一个模板解析变量,一次打断一行,将行传递给第二个命名模板,该模板将字符序列解析为tr
元素序列。在伪代码中,类似这样的东西:
template name="emit-rows"
param name="input"
choose when $input = ''
// do nothing
otherwise
<tr>
call-template name="emit-columns"
with-param name="s"
value="substring-before($input,'
')
</tr>
call-template name="emit-rows"
with-param name="input"
value="substring-after($input,'
')
template name="emit-columns"
param name="s"
choose when $s = ''
<!--* do nothing *-->
otherwise
<td>
value-of substring-before($s,'|')
</td>
call-template name="emit-columns"
with-param name="s" value="substring-after($s,'|')
这里有一个简单的Perl脚本,可以执行
my $tag = "th";
while(<>)
{
s/[rn]*$//;
print "<$tag>n";
for $f (split /|/)
{
print "<td>$f</td>n";
}
print "</$tag>n";
$tag = "tr";
}
您可能需要根据运行位置来调整字符编码(WIndows与Linux),以确保您的重音字符不会被破坏。我把它留给你练习。
以下是您输入的前3行的输出:
<th>
<td>D▒tail</td>
<td>Num▒ro appel▒</td>
<td>Date et heure</td>
<td>Quantit▒ r▒elle</td>
<td>Qantit▒ factur▒e</td>
<td>H.T.</td>
<td>T.T.C.</td>
</th>
<tr>
<td>Appel vers un portable</td>
<td>06110XXXXX</td>
<td>14/06 - 09h32</td>
<td>00h00mn23s</td>
<td>00h00mn23s</td>
<td>gratuit</td>
<td>gratuit</td>
</tr>
<tr>
<td>Appel vers un portable</td>
<td>06889XXXXX</td>
<td>14/06 - 10h39</td>
<td>00h01mn16s</td>
<td>00h01mn16s</td>
<td>gratuit</td>
<td>gratuit</td>
</tr>