Search code examples
xmlxsltapache-cocoon

Matching selector when in Cocoon depending on another xml file


I'm trying to write a pipeline in Cocoon that matches a pattern of "*.myxml" that then reads (with generate type="file") a XML file. This XML file is formed like this (with many files):

<result>
   <file>
       <name>a.myxml</name>
       <source>b.xml</source>
       <transform>c.xslt</transform>
   </file>
   ...
</result>

So if the pattern is a.myxml, I want to read b.xml and apply c.xslt, all this dynamically using this XML file. I want to be able to add new files (with their own .xml and .xslt) without having to modify the pipeline every time.

Is it possible? Is there a selector for this? Is there a way to pass the content of the XML file (like a XPath selector file[/name = {1}.myxml]/source or something) as the src of the generate and the transform?

Thank you for your help.


Solution

  • it's slightly more complex than usual in Cocoon, but I created a sample of what I think you're after.

    In the sitemap:

    <map:pipeline>
      <map:match pattern="*.myxml">
        <map:generate src="my.xml"/>
        <map:transform src="sf-myxml.xslt">
          <map:parameter name="myxml" value="{1}.myxml"/>
        </map:transform>
        <map:transform type="include"/>
        <map:serialize type="xml"/>
      </map:match>
    
      <map:match pattern="myxml/**">
        <map:generate src="{1}"/>
        <map:transform src="{request-param:stylesheet}"/>
        <map:serialize type="xml"/>
      </map:match>
    </map:pipeline>
    

    So, matching *.myxml generates XML from the dynamic configuration file.

    <result>
      <file>
        <name>a.myxml</name>
        <source>b.xml</source>
        <transform>c.xslt</transform>
      </file>
    
      <file>
        <name>x.myxml</name>
        <source>y.xml</source>
        <transform>c.xslt</transform>
      </file>
    
    </result>
    

    Using sf-myxml.xslt this is transformed to a Cinclude call:

     <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
       xmlns:xs="http://www.w3.org/2001/XMLSchema"
       xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
       xmlns:ci="http://apache.org/cocoon/include/1.0"
       exclude-result-prefixes="xs xd"
       version="2.0">
    
    
      <xsl:param name="myxml"/>
    
      <xsl:template match="/result">
        <xsl:copy>
            <xsl:apply-templates select="file[name eq $myxml]"/>
        </xsl:copy>
      </xsl:template>
    
    
      <xsl:template match="file">
        <ci:include src="cocoon:/myxml/{source}?stylesheet={transform}"/>
      </xsl:template>
    
    
    </xsl:stylesheet>
    

    by finding the right <file> element and using the <source> and <transform> elements. For example for the call "/a.myxml" this generates:

     <ci:include src="cocoon:/myxml/b.xml?stylesheet=c.xslt"/>
    

    This cocoon:/ call in the <cinclude> is then matched by the next <map:match>, where, in the above example, b.xml is transformed by c.xslt. I tried it and it works.

    Here's b.xml:

    <page/>
    

    Here's y.xml:

    <page title="z.myxml"/>
    

    Here's c.xslt:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
      exclude-result-prefixes="xs xd"
      version="2.0">
    
      <xsl:template match="page">
        <html><head><title><xsl:value-of select="@title"/></title></head><body><h1><xsl:value-of select="@title"/></h1></body></html>
      </xsl:template>
    
    </xsl:stylesheet>
    

    I get no title when calling a.myxl and a title "z.myxml" when calling z.myxml. Hope this is what you were looking for.

    Regards,

    Huib Verweij.