2

I have the following node I need to parse using XSLT 1.0 from xml file

<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>

Here is the -ID: -Log:

as you can see can be written on one line or on multiple lines.

In result I would like to get another xml file where the data from node will be parsed. If record with ID was Passed then I need to write "/>. If record was Failed then I need to write

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

In other words I need to get this xml file.

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

What do you think can be best way to do this?

The xml file is actually very big and I provided here only one node I need to parse. I'm using xslt because I'm getting other information from other nodes which I also need for result xml files.

Thank you.

7
  • I'm afraid that XSL can only parse XML files to generate text output and not the other way round. Commented May 18, 2011 at 15:12
  • do you really have to do this with XSLT? The input file seems to be a very simple XML, and you actually want to process the text inside the single log element. So, you may want to write some code in a programming language that makes it easy to process text and produce an XML as output. You have several choices: Perl, Java, ... Commented May 18, 2011 at 15:15
  • @Cobra_Fast, thank you. I have already wrote comments to your reply but seems you removed it. You can parse xml files to get another xml files. Commented May 18, 2011 at 15:15
  • @MacroS, thank you. The xml file is actually very big and I provided here only one node I need to parse. I'm using xslt because I'm getting other information from other nodes which I also need for result xml files. Commented May 18, 2011 at 15:17
  • If your requirement is using pure XSLT to do that task you have with XSLT 2.0 tokenize(). Can you use XSLT 2.0? Commented May 18, 2011 at 15:43

2 Answers 2

2

XSLT is not the right technology for this task. XSLT is fantastic at transforming the structure of XML documents (typically to another XML document, but XML-to-text is also possible). XSLT is not good for parsing text and manipulating it.

What you have is some structured text that happens to be within an XML element.

I would opt for another transformation technique, Regex, or simple string parsing methods.

Sign up to request clarification or add additional context in comments.

2 Comments

I have updated initial question with information why I use xslt.
I see your point of view, but the current OP question was very feasible. XSLT 2.0 is really undervalued on regex tasks. See my answer.
0

The following XSLT demonstrates how to split log content in tokens just using tokenize(). There are probably better choices with XSLT 2.0 (for example xsl:analyze-string), but because of using tokenize() only, this solution is applicable also to XSLT 1.0 extended with EXSLT templates.


XSLT 2.0 tested on Saxon-B 9.0.0.2J

<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>

The above XSLT applied on the following input:

<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>

Produces the following output:

<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>

Note that &#xA; is due to line-feeds of the source text appearing because we are placing the content inside the attribute value. To get rid of that it would be better to include the message as content of the element failure. Anyway the following article deals with tricky spaces.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.