使用XSLT解析多行

时间:2011-05-18 15:05:59

标签: xml xslt

我需要使用xml文件中的XSLT 1.0解析以下节点

<log>Passed -ID:1 -Log:
Passed -ID:2 -Log:Suite
File/Folder
Failed -ID:3 -Log:Suite
Validate Install Failed
Passed -ID:4 -Log:
</log>

这是-ID:-Log:

你可以看到

可以写在一行或多行。

结果我想获得另一个xml文件,其中将解析来自节点的数据。如果带有ID的记录已通过,那么我需要写“/&gt;”。 如果记录失败,那么我需要写

<testcase name="<ID Name>">
  <failure message="<Log Message>"/>
</testcase>

换句话说,我需要获取这个xml文件。

<xml>
   <testcase name="1"/>
   <testcase name="2"/>
   <testcase name="3">
      <failure message="Suite Validate Install Failed"/>
   </testcase>
   <testcase name="4"/>
</xml>

您认为最好的方法是什么?

xml文件实际上非常大,我在这里只提供了一个我需要解析的节点。我正在使用xslt,因为我从其他节点获取其他信息,我也需要结果xml文件。

谢谢。

2 个答案:

答案 0 :(得分:2)

XSLT不适合执行此任务。 XSLT非常适合转换XML文档的结构(通常是另一个XML文档,但也可以使用XML到文本)。 XSLT不适合解析文本和操作它。

您所拥有的是一些恰好位于XML元素中的结构化文本。

我会选择另一种转换技术,Regex或简单的字符串解析方法。

答案 1 :(得分:0)

以下 XSLT 演示了如何使用log在令牌中拆分tokenize()个内容。使用 XSLT 2.0 (例如xsl:analyze-string)可能有更好的选择,但由于仅使用tokenize(),此解决方案也适用于 XSLT 1.0 使用 EXSLT 模板进行扩展。


Saxon-B 9.0.0.2J 上测试

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:strip-space elements="*"/>


    <xsl:template match="/">
        <xml>
            <xsl:variable name="string" select="."/>

            <xsl:variable name="pass" select="tokenize($string,'Passed -ID:')[not(position()=1)]"/>

            <xsl:for-each select="$pass">

                <xsl:choose>
                    <xsl:when test="contains(.,'Failed -ID:')">
                        <xsl:variable name="failure" select="tokenize(.,'Failed -ID:')"/>

                        <xsl:for-each select="$failure">
                            <xsl:choose>
                                <xsl:when   test="position()=1">
                                    <testcase name="{tokenize(.,'\s-Log:')[1]}"/>
                                </xsl:when>
                                <xsl:otherwise>
                                    <xsl:variable name="tc" select="tokenize(.,'\s-Log:')"/>
                                    <testcase name="{$tc[1]}">
                                        <failure message="{$tc[2]}"/>
                                    </testcase>
                                </xsl:otherwise>
                            </xsl:choose>
                        </xsl:for-each>
                    </xsl:when>

                    <xsl:otherwise>
                        <testcase name="{tokenize(.,'\s-Log:')[1]}"/>
                    </xsl:otherwise>

                </xsl:choose>
            </xsl:for-each>
            <xsl:apply-templates/>
        </xml>
    </xsl:template>

    <xsl:template match="log"/>


</xsl:stylesheet>

以上XSLT应用于以下输入:

<log>Passed -ID:1 -Log:
Passed -ID:2 -Log:Suite
File/Folder
Failed -ID:3 -Log:Suite
Validate Install Failed
Passed -ID:4 -Log:
Failed -ID:5 -Log:aaaaaa
Failed -ID:6 -Log:dfsfsdf
Failed -ID:7 -Log:dsfsfs
fsdfsdfsdfsdfs
Passed -ID:8 -Log:dfsdfsf
Failed -ID:9 -Log:dfsdfs
</log>

产生以下输出:

<xml>
   <testcase name="1"/>
   <testcase name="2"/>
   <testcase name="3">
      <failure message="Suite&#xA;Validate Install Failed&#xA;"/>
   </testcase>
   <testcase name="4"/>
   <testcase name="5">
      <failure message="aaaaaa&#xA;"/>
   </testcase>
   <testcase name="6">
      <failure message="dfsfsdf&#xA;"/>
   </testcase>
   <testcase name="7">
      <failure message="dsfsfs&#xA;fsdfsdfsdfsdfs&#xA;"/>
   </testcase>
   <testcase name="8"/>
   <testcase name="9">
      <failure message="dfsdfs&#xA;"/>
   </testcase>
</xml>

请注意,&#xA;是由于我们将内容放在属性值中而导致出现源文本的换行符。为了摆脱这种情况,最好将消息包含为元素failure的内容。无论如何following article处理棘手的空间。