How to process all data from multiple XML files after merging using XSL

I use XSL to read in three XML documents that are identical, except that their attributes have different meanings (maybe I will read many XML files). I want to count the number of times the attribute "result" has the value "Passed" or "Failed" for an element with the attribute "testName" = "TestOne". I achieve this using the following:

File1.xml

<container> <build> <Tests> <Results> <Result testName="TestOne" outcome="Passed" ></Result> <Result testName="TestTwo" outcome="Passed" ></Result> </Results> </Tests> </build> </container> 

File2.xml

 <container> <build> <Tests> <Results> <Result testName="TestOne" outcome="Passed" ></Result> <Result testName="TestTwo" outcome="Failed" ></Result> </Results> </Tests> </build> </container> 

File3.xml

 <container> <build> <Tests> <Results> <Result testName="TestOne" outcome="Failed" ></Result> <Result testName="TestTwo" outcome="Failed" ></Result> </Results> </Tests> </build> </container> 

Index.xml

 <?xml-stylesheet type="text/xsl" href="merge3.xsl"?> <list> <entry name="File1.xml" /> <entry name="File2.xml" /> <entry name="File3.xml" /> </list> 

Merge2.xsl

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/> <xsl:template match="/"> <xsl:for-each select="/list/entry"> <xsl:apply-templates select="document(@name)/container/build/*[local-name()='Tests']" /> </xsl:for-each> </xsl:template> <xsl:template match="*[local-name()='Results']"> <xsl:variable name="name" select="'TestOne'" /> <xsl:variable name="totalPassed" select="*[local-name()='Result'][@testName = 'TestOne'][@outcome = 'Passed']" /> <xsl:variable name="totalFailed" select="*[local-name()='Result'][@testName = 'TestOne'][@outcome = 'Failed']" /> <h2>Totals</h2> <table border="1" cellSpacing="0" cellPadding="5" > <tr bgcolor="#9acd32"> <th>Test Name</th> <th>Total Passed</th> <th>Total Failed</th> </tr> <tr> <td><xsl:value-of select="$name"/></td> <td><xsl:value-of select="count($totalPassed)"/></td> <td><xsl:value-of select="count($totalFailed)"/></td> </tr> </table> </xsl:template> </xsl:stylesheet> 

The result is 3 Totals tables. My intention is to display one Totals table showing how many times TestOne passed and failed in all XML documents. It seems that each XML document is read / selected, and then processed one at a time. I would like to read and select all the XML files before processing them.

+6
source share
2 answers

You can collect all Result elements from three documents using something like

 <xsl:variable name="allResults" select="(/ | document('file2.xml') | document('file3.xml'))//Result" /> 

and then apply predicates to this to count the elements you are interested in, for example

 <xsl:value-of select=" count($allResults[@testName = 'TestOne'][@outcome = 'Failed'])" /> 

Instead of a fixed set of file names, if you have a basic index.xml that lists all the files you want to merge, for example:

 <list> <entry name="File1.xml" /> <entry name="File2.xml" /> <entry name="File3.xml" /> </list> 

then you can use this index as the main input to the stylesheet, and the allResults variable will look like this:

 <xsl:variable name="allResults" select="document(/list/entry/@name)//Result" /> 

When you pass the node installed in the document function, it takes a string value of each node in turn and treats it as the URI of the loaded file, returning the result set of the document root nodes.

Here is a complete example.

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/> <xsl:variable name="allResults" select="document(/list/entry/@name)//Result" /> <xsl:template match="/"> <xsl:variable name="name" select="'TestOne'" /> <h2>Totals</h2> <table border="1" cellSpacing="0" cellPadding="5" > <tr bgcolor="#9acd32"> <th>Test Name</th> <th>Total Passed</th> <th>Total Failed</th> </tr> <tr> <td><xsl:value-of select="$name"/></td> <td><xsl:value-of select="count($allResults[@testName = $name] [@outcome = 'Passed'])"/></td> <td><xsl:value-of select="count($allResults[@testName = $name] [@outcome = 'Failed'])"/></td> </tr> </table> </xsl:template> </xsl:stylesheet> 
+9
source

This is almost the same as above, but without a variable.

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/> <xsl:template match="/"> <h2>Totals</h2> <table border="1" cellSpacing="0" cellPadding="5" > <tr bgcolor="#9acd32"> <th>Test Name</th> <th>Total Passed</th> <th>Total Failed</th> </tr> <xsl:for-each select="/list/entry"> <tr> <td><xsl:value-of select="@name"/></td> <td><xsl:value-of select="count(document(@name)/container/build/Tests/Results/Result[@outcome eq 'Passed'])"/></td> <td><xsl:value-of select="count(document(@name)/container/build/Tests/Results/Result[@outcome eq 'Failed'])"/></td> </tr> </xsl:for-each> </table> </xsl:template> </xsl:stylesheet> 
0
source

Source: https://habr.com/ru/post/952880/


All Articles