Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old October 16th, 2012, 09:54 AM
Authorized User
 
Join Date: Mar 2012
Posts: 25
Thanks: 9
Thanked 0 Times in 0 Posts
Default How to obtain permutations of a set of values?

Dear forum's users!

I hope you'll be able to answer to my two questions (below), but let's start from an example:

Imagine to have a set of nodes defining constant names and respective types, like:
<valueDef>
<constant name="c1" />
<type name="t1" />
</valueDef>

Imagine to have c1, ..., c5 of type t1 and c6, ..., c10 of type t2.

Now, my goal is to generate all possible permutations of pairs of constants of the two types:

c1,c6
c1,c7
c1,c8
c1,c9
c1,c10
c2,c6
c2,c7
c2,c8
c2,c9
c2,c10
...

I need to do that in order to create all possible terms f(A,B) where A has type t1 and B has type t2. Then I have to add that function to the resulting tree in a form similar to:

<function name="t">
<argument><constant name="c1" /><argument>
<argument><constant name="c6" /><argument>
</function>

Creating the function node is simple, but collecting all combinations of arguments is the real challenge (at least for me ).

Is there a way to do that? Would it be possible to apply the same method also in the case you do not know in advance the number of arguments of "f" (suppose you always know the types, it is simple to query the original tree to check the definition of the function "f" and thus the number of arguments, but you can't know that before writing the script )?

Bonus question : What would you do if you had to generate one output file for each generated "f"-term?

Thanks in advance!

PS: I already considered groups but I didn't find a way to use them efficiently for my purpose. They are for sure useful to collect all constants names (grouping by type)
 
Old October 16th, 2012, 12:28 PM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

Assuming XSLT 2.0 here is a sample that shows to compute the permutations of two sequences (of strings in the sample but that does not really matter):
Code:
<xsl:stylesheet 
  version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="text"/>

<xsl:template name="main">
  <xsl:variable name="seq1" select="'c1', 'c2', 'c3', 'c4', 'c5'"/>
  <xsl:variable name="seq2" select="'c6', 'c7', 'c8', 'c9', 'c10'"/>
  
  <xsl:for-each select="$seq1">
    <xsl:variable name="item1" select="."/>
    <xsl:for-each select="$seq2">
      <xsl:value-of select="concat($item1, ',', ., '
')"/>
    </xsl:for-each>
  </xsl:for-each>
  
</xsl:template>

</xsl:stylesheet>
To generate several result documents with XSLT 2.0 and an XSLT 2.0 processor like Saxon 9 or AltovaXML you can use xsl: result-document, see http://www.saxonica.com/documentatio...t-document.xml
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
The Following User Says Thank You to Martin Honnen For This Useful Post:
EastvanAxon (October 16th, 2012)
 
Old October 16th, 2012, 01:11 PM
Authorized User
 
Join Date: Mar 2012
Posts: 25
Thanks: 9
Thanked 0 Times in 0 Posts
Default

Thanks Martin for your reply!

Quote:
Originally Posted by Martin Honnen View Post
Assuming XSLT 2.0 here is a sample that shows to compute the permutations of two sequences (of strings in the sample but that does not really matter):
Code:
<xsl:stylesheet 
  version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="text"/>

<xsl:template name="main">
  <xsl:variable name="seq1" select="'c1', 'c2', 'c3', 'c4', 'c5'"/>
  <xsl:variable name="seq2" select="'c6', 'c7', 'c8', 'c9', 'c10'"/>
Since I don't know in advance how many constant symbols are present in the original tree, can I replace the select value (i.e. explicit list of strings 'ci', ..., 'ci+5') with a XPath selecting all the value from the tree (grouping them from types)? Probably Iìll need to do two steps: first collect the nodes belonging to one type and then extract only the constant names, right?

Quote:
Code:
  <xsl:for-each select="$seq1">
    <xsl:variable name="item1" select="."/>
    <xsl:for-each select="$seq2">
      <xsl:value-of select="concat($item1, ',', ., '
')"/>
    </xsl:for-each>
  </xsl:for-each>
  
</xsl:template>

</xsl:stylesheet>
To generate several result documents with XSLT 2.0 and an XSLT 2.0 processor like Saxon 9 or AltovaXML you can use xsl: result-document, see http://www.saxonica.com/documentatio...t-document.xml
Yes, I'm using XSLT 2.0. But since I have to copy the entire original tree and just add to each output file a new function in a precise spot, where do you suggest me to use xsl:result-document? I already use that feature for other scripts. For example, I'm not sure the best place would be in the innermost xsl:for-each because how could I copy the entire tree from there (assuming I have already explored it with other templates in order to collect information about "f" ariety and constant symbols)?

On top of that, note that I cannot use, for my final script, the following
Code:
  <xsl:for-each select="$seq1">
    <xsl:variable name="item1" select="."/>
    <xsl:for-each select="$seq2">
      <xsl:value-of select="concat($item1, ',', ., '
')"/>
    </xsl:for-each>
  </xsl:for-each>
since I don't know in advance that "f" takes 2 arguments. That is also an information I have to obtain from the original tree. Do you have any suggestions for this problem?

Thanks again for your help!
Best,
Eastvan
 
Old October 16th, 2012, 01:41 PM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

Well with
Code:
<valueDef>
<constant name="c1" />
<type name="t1" />
</valueDef>
being your input you probably want to group them by the type name e.g.
Code:
<xsl:variable name="sequences" as="element(seq)">
  <xsl:for-each-group select="//valueDef" group-by="type/@name">
    <seq type="{current-grouping-key()}">
       <xsl:for-each select="current-group()/constant/@name">
          <value><xsl:value-of select="."/></value>
       </xsl:for-each>
    </seq>
  </xsl:for-each-group>
</xsl:variable>
So that way you have your input sequences in an XML format you can process further.

The sequence literals in my first answer are just an example I could easily construct from your sample data in the input post.

As for producing several output files with a complete tree with the function call added, I would like to see more concrete input sample data before I try to spell out code. I am also currently not sure where you want to find the number of arguments, would that be the number of different types the above sample finds by grouping the "valueDef" elements?
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old October 17th, 2012, 05:45 AM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

I tried to make up some sample data and then wrote some code, here it goes, with the input sample being
Code:
<data>
<valueDef>
    <constant name="c1" />
    <type name="t1" />
</valueDef>
<valueDef>
    <constant name="c2" />
    <type name="t1" />
</valueDef>
<valueDef>
    <constant name="c3" />
    <type name="t1" />
</valueDef>
<valueDef>
    <constant name="c4" />
    <type name="t2" />
</valueDef>
<valueDef>
    <constant name="c5" />
    <type name="t2" />
</valueDef>
<valueDef>
    <constant name="c6" />
    <type name="t3" />
</valueDef>
<valueDef>
    <constant name="c7" />
    <type name="t3" />
</valueDef>
</data>
I wrote the stylesheet
Code:
<xsl:stylesheet 
  version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:mf="http://example.com/mf"
  exclude-result-prefixes="xs mf">

<xsl:param name="function-name" as="xs:string" select="'f'"/>
<xsl:variable name="main-doc" as="document-node()" select="/"/>

<xsl:output method="xml" indent="yes"/>

<xsl:function name="mf:permute" as="element(function)*">
  <xsl:param name="function-name" as="xs:string"/>
  <xsl:param name="input-sequences" as="element(seq)*"/>
  <xsl:param name="result-arguments" as="xs:string*"/>
  <xsl:sequence 
     select="$input-sequences[1]/value/mf:permute-values(
               $function-name,
               $input-sequences[position() gt 1], 
               ($result-arguments, .))"/>
</xsl:function>

<xsl:function name="mf:permute-values" as="element(function)*">
  <xsl:param name="function-name" as="xs:string"/>
  <xsl:param name="input-sequences" as="element(seq)*"/>
  <xsl:param name="result-arguments" as="xs:string*"/>
  <xsl:choose>
    <xsl:when test="not($input-sequences)">
      <function name="{$function-name}">
        <xsl:for-each select="$result-arguments">
          <argument>
            <constant name="{.}"/>
          </argument>
        </xsl:for-each>
      </function>
    </xsl:when>
    <xsl:otherwise>
      <xsl:sequence 
        select="$input-sequences[1]/value/mf:permute-values(
                   $function-name,
                   $input-sequences[position() gt 1],
                   ($result-arguments, .))"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:variable name="sequences" as="element(seq)*">
  <xsl:for-each-group select="//valueDef" group-by="type/@name">
    <seq type="{current-grouping-key()}">
       <xsl:for-each select="current-group()/constant/@name">
          <value><xsl:value-of select="."/></value>
       </xsl:for-each>
    </seq>
  </xsl:for-each-group>
</xsl:variable>

<xsl:variable name="function-calls" as="element(function)*">
  <xsl:sequence select="mf:permute($function-name, $sequences, ())"/>
</xsl:variable>

<xsl:template match="/">
  <debug>
    <xsl:copy-of select="$sequences"/>
  </debug>
  <debug>
    <xsl:copy-of select="$function-calls"/>
  </debug>
  <xsl:apply-templates select="$function-calls" mode="doc"/>
</xsl:template>

<xsl:template match="function" mode="doc">
  <xsl:result-document href="{@name}{position()}.xml">
    <xsl:apply-templates select="$main-doc/node()">
      <xsl:with-param name="function-call" as="element(function)" select="current()" tunnel="yes"/>
    </xsl:apply-templates>
  </xsl:result-document>
</xsl:template>
  
<xsl:template match="@* | node()">
  <xsl:copy>
    <xsl:apply-templates select="@* , node()"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="data">
  <xsl:param name="function-call" as="element(function)" tunnel="yes"/>
  <xsl:copy>
    <xsl:apply-templates select="@* , node()"/>
    <xsl:sequence select="$function-call"/>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>
which, when applied with Saxon 9.4 HE, outputs the following primary result
Code:
<debug>
   <seq type="t1">
      <value>c1</value>
      <value>c2</value>
      <value>c3</value>
   </seq>
   <seq type="t2">
      <value>c4</value>
      <value>c5</value>
   </seq>
   <seq type="t3">
      <value>c6</value>
      <value>c7</value>
   </seq>
</debug>
<debug>
   <function name="f">
      <argument>
         <constant name="c1"/>
      </argument>
      <argument>
         <constant name="c4"/>
      </argument>
      <argument>
         <constant name="c6"/>
      </argument>
   </function>
   <function name="f">
      <argument>
         <constant name="c1"/>
      </argument>
      <argument>
         <constant name="c4"/>
      </argument>
      <argument>
         <constant name="c7"/>
      </argument>
   </function>
   <function name="f">
      <argument>
         <constant name="c1"/>
      </argument>
      <argument>
         <constant name="c5"/>
      </argument>
      <argument>
         <constant name="c6"/>
      </argument>
   </function>
   <function name="f">
      <argument>
         <constant name="c1"/>
      </argument>
      <argument>
         <constant name="c5"/>
      </argument>
      <argument>
         <constant name="c7"/>
      </argument>
   </function>
   <function name="f">
      <argument>
         <constant name="c2"/>
      </argument>
      <argument>
         <constant name="c4"/>
      </argument>
      <argument>
         <constant name="c6"/>
      </argument>
   </function>
   <function name="f">
      <argument>
         <constant name="c2"/>
      </argument>
      <argument>
         <constant name="c4"/>
      </argument>
      <argument>
         <constant name="c7"/>
      </argument>
   </function>
   <function name="f">
      <argument>
         <constant name="c2"/>
      </argument>
      <argument>
         <constant name="c5"/>
      </argument>
      <argument>
         <constant name="c6"/>
      </argument>
   </function>
   <function name="f">
      <argument>
         <constant name="c2"/>
      </argument>
      <argument>
         <constant name="c5"/>
      </argument>
      <argument>
         <constant name="c7"/>
      </argument>
   </function>
   <function name="f">
      <argument>
         <constant name="c3"/>
      </argument>
      <argument>
         <constant name="c4"/>
      </argument>
      <argument>
         <constant name="c6"/>
      </argument>
   </function>
   <function name="f">
      <argument>
         <constant name="c3"/>
      </argument>
      <argument>
         <constant name="c4"/>
      </argument>
      <argument>
         <constant name="c7"/>
      </argument>
   </function>
   <function name="f">
      <argument>
         <constant name="c3"/>
      </argument>
      <argument>
         <constant name="c5"/>
      </argument>
      <argument>
         <constant name="c6"/>
      </argument>
   </function>
   <function name="f">
      <argument>
         <constant name="c3"/>
      </argument>
      <argument>
         <constant name="c5"/>
      </argument>
      <argument>
         <constant name="c7"/>
      </argument>
   </function>
</debug>
and twelve result documents f1.xml to f12.xml (where for instance f1.xml is)
Code:
<data>
   <valueDef>
      <constant name="c1"/>
      <type name="t1"/>
   </valueDef>
   <valueDef>
      <constant name="c2"/>
      <type name="t1"/>
   </valueDef>
   <valueDef>
      <constant name="c3"/>
      <type name="t1"/>
   </valueDef>
   <valueDef>
      <constant name="c4"/>
      <type name="t2"/>
   </valueDef>
   <valueDef>
      <constant name="c5"/>
      <type name="t2"/>
   </valueDef>
   <valueDef>
      <constant name="c6"/>
      <type name="t3"/>
   </valueDef>
   <valueDef>
      <constant name="c7"/>
      <type name="t3"/>
   </valueDef>
   <function name="f">
      <argument>
         <constant name="c1"/>
      </argument>
      <argument>
         <constant name="c4"/>
      </argument>
      <argument>
         <constant name="c6"/>
      </argument>
   </function>
</data>
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old October 17th, 2012, 06:06 AM
Authorized User
 
Join Date: Mar 2012
Posts: 25
Thanks: 9
Thanked 0 Times in 0 Posts
Default

I'll study your stylesheet in details as soon as possible. At first sight it seems to be perfect for my purposes.

I'll let you know if I'll be able to adapt it for the real input I have to deal with (I think it's just a matter of finding the time now that you helped me ^_^)

In the meantime, thank you very much Martin!

Last edited by EastvanAxon; October 17th, 2012 at 08:50 AM.. Reason: typos





Similar Threads
Thread Thread Starter Forum Replies Last Post
data set row values MunishBhatia ASP.NET 2.0 Professional 0 November 16th, 2007 11:52 PM
Is it possible to store "SET" values to Vector ? msg2ajay JSP Basics 1 September 4th, 2007 06:45 AM
how Set Multiple values in cookies amol_0008 JSP Basics 1 May 31st, 2007 06:27 AM
Help with allocating invoices - permutations skt1974 Excel VBA 1 January 10th, 2007 09:23 AM
Using VB to get and set values in exchange 5.5 elfranger VB.NET 2002/2003 Basics 0 April 20th, 2004 07:50 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.