Question

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.

Was it helpful?

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top