You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cocoon.apache.org by Alain Pannetier <al...@gmail.com> on 2006/08/17 22:31:17 UTC

Parsing sitemap from within XSLT Transformer

Dear list,

Problem :

I am in a situation in which I need to know from within an XSLT
transformer what matcher will be selected for a given URL.


Use case :

To address SVG cross browser portability issues from the server side,
I've put a little bit of logic in my sitemap to decide whether a given
SVG URL must be sent as plain SVG or should rather fall back to a
rasterized substitute.

<map:match pattern="**/*somepattern*.svg">
  <map:act type="diagram-format">
    <map:parameter name="svg_rule_1" value="outcome = svg;
MSIE_version >= 4;      ASV_version >= 3.0" />
    <map:parameter name="svg_rule_2" value="outcome = svg;
MSIE_version >= 7.2;    NativeSupport == 1" />
    <map:parameter name="svg_rule_3" value="outcome = svg;
Firefox_version >= 1.0; NativeSupport == 0; ASV_version>=6.0" />
    <map:parameter name="svg_rule_4" value="outcome = svg;
Firefox_version >= 3.0; NativeSupport == 1" />
    <map:parameter name="svg_rule_5" value="outcome = svg;
Gecko_version >= 1.9;   NativeSupport == 1" />
    <map:parameter name="svg_rule_6" value="outcome = svg;
Gecko_version >= 1.7;   NativeSupport == 0; ASV_version >= 6.0" />
    <map:parameter name="svg_rule_7" value="outcome = svg;
Opera_version >= 9.0;   NativeSupport == 1" />
    <map:select type="parameter">
      <map:parameter name="parameter-selector-test" value="{diagramType}"/>
      <map:when test="svg">
        <map:read mime-type="image/svg+xml" src="{../1}/{../2}.svg"/>
      </map:when>
      <map:when test="bitmap">
        <map:generate src="{../1}/{../2}.svg" />
        <map:serialize type="svg2png">
          <parameter name="EXECUTE_ONLOAD" type="boolean" value="true"/>
        </map:serialize>
      </map:when>
      <map:otherwise>
        <map:generate src="xml/dummy.xml" />
        <map:transform src="xslt/message.xslt">
          <map:parameter name="message" value="Unknown diagram type
{diagramType}. Expecting one of 'svg', 'bitmap'." />
        </map:transform>
        <map:serialize type="html"/>
      </map:otherwise>
    </map:select>
  </map:act>
</map:match>

Because I've got different matchers, I can have a different set of
compliance rules for different urls.

So far so good.  In case you wonder the browser info against witch the
rules are tallied comes from an ad-hoc cookie sent by the browser.

The complication comes from the fact that depending on the form of the
image, the containing xhtml page will need to include it in an <img>
tag, an <embed> or an <object> tag.  The output can theoretically
contain SVG from any of the various SVG matchers.  This rules out
simply duplicating the configuration rules : they are different.
I know it actually kind of works to include a PNG in an embed tag but
I'd prefer not to rely on this 'feature' (Nevertheless, that's Plan
C).

For now I'm willing to spend some time to try write a Xalan extension
along the line of

<xs:param name="sitemap"/>

<xsl:template match="picture">
   <xsl:variable name="outcome" select="myExtClass:getOutcome($sitemap,@src)"/>
   <xsl:chose>
      <xsl:when test="$outcome == 'svg'">
         <embed .../>
      </xsl:when>
      <xsl:when test="$outcome == 'bitmap'">
         <img src="{@src}"/>
      </xsl:when>
   </xsl:chose>
</xsl:template>


True, I could probably parse the sitemap, passed as sitemap parameter
and obtained through {contextrealpath:sitemap.xmap}, from within the
XSL as well (Plan B) but a more elegant
solution could also be to create a Xalan java extension by
  - building a TreeProcessor
    <xsl:variable name="processor"
select="java:org.apache.cocoon.components.treeprocessor.TreeProcessor"/>
 - somehow find out what matcher is selected.
That's plan A.

  I know that seems wildly outlandish but OTOH I never cease to be
amazed by cocoon's versatility and I can't be the first pimply nerd to
come across this requirement.
 So that I wouldn't be astounded if someone comes forward and say
"Sure, use such-and-such, we guys do that every day".

Any idea ?

Thx in advance

Alain Pannetier.

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@cocoon.apache.org
For additional commands, e-mail: users-help@cocoon.apache.org


Re: Parsing sitemap from within XSLT Transformer

Posted by Alain Pannetier <al...@gmail.com>.
Dear Toby,

Thank you for your help.
Your suggestion is interresting. I'm still mulling it over.

Reading your second post yet another time I believe I understand what
you're saying.
You're suggesting to
  - pre-compute all the behaviours of all the matchers that would generate SVG
  - make the corresponding outcome available to all matchers through
sitemap parameters.
That's a good idea.  If you don't have too many SVG matchers of
course, but that's a fair assumption  since they are generated by
various XSLT.

You probably think I'm addicted to Xalan extensions but I believe I
will still need the help of the WildcardHelper to work out to what
matcher the SVG source URI belongs from within the XSLT.

Let me clarify this.

XSLT knows
   - the src attribute of the picture
   - the wildcards/outcome pairs of the various SVG matchers for the
current user's user agent configuration
(n.b. outcome := 'svg'|'bitmap' - a wildcard/outcome pair :
'easy/*.svg' => 'svg').

It still needs to match one with the other.

Below are more considerations in random order.

Suppose a given document must contain two SVG images :
  -  first SVG is easy and can be rendered by most browsers.
  - second SVG is more sophisticated and will be rasterized for some browsers.

The XML form of the document is sth like

<doc>
   <paragraph>
      Blah Blah
      <figure src="easysvg"/>
      Blah Blah
      <figure src="complexSVG"/>
      Blah Blah
   </paragraph>
</doc>

The sitemap has several set of rules depending on the complexity of the SVG :
  - The matcher for easySVG for example allows all browsers to render SVG.
  - The matcher for complexSVG falls back to raster when the browser
is Firefox (e.g. SVG includes filters, unsupported by FF)

For Firefox, the transformer generating XHTML is supposed to emit

...
<p>Blah Blah</p>
<embed src="easySVG"/>
<p>Blah Blah</p>
<img src="complexSVG"/>
<p>Blah Blah</p>
...

The XSL needs to know what form complexSVG will take so as to generate
an <img> tag, even though easySVG may take another form : <embed>.
In other words SVG() is not simply a function of the browser but of
the browser capabilities as well as the SVG complexity.
Please note that you don't even need these two SVGs to be located in
the same document to run into the problem.  It's enough that two
documents are generated by the same XSLT and one includes the easy SVG
whereas the other includes the complex SVG.

And I can have many XSLT matchers and many SVG matchers.

When I write the XSLT I'm not supposed to code the rules again
otherwise that means I need to maintain two copies of [possibly
numerous] rules one in the sitemap and one in the XSL (possibly many
as well, could <xsl:import ... though).
Putting the rules at the matcher level allowed me to have different
rules for different URLs.  It's just that they're "hidden" from the
matcher that generates the XHTML document.
Putting them 'above' is OK, I just need the outcome to be visible to
the selectors.

You'll probably  argue that a faster strategy would be to tailor the
SVG upstream to avoid 'complexity' for browsers with weak SVG support.
I'm doing that already.  Especially because DOMs are relatively different.

Alain Pannetier

P.S. I recall times when I thought XHTML/CSS cross browser
compatibility was hard :-(

On 8/18/06, Toby <to...@linux.it> wrote:
> Alain Pannetier wrote:
> > Toby wrote:
> > > you could put the action around everything, as the first and only
> > > child of <map:pipelines>  [...] modify it so that it only computes
> > > diagramType on the first request of every session, and then it just
> > > returns a cached value.
> >
> > This is actually what I started doing but then it finally dawned on me
> > that a given document or a given pattern generating various document
> > needs to cater for various types of SVG documents.
>
> I don't understand your point very well.
>
> You say that a document or a pattern needs to cater to various SVG
> needs.  That's exactly why I suggested passing a parameter to the XSLT.
>
> This is how I think it would work:
> - the user opens the browser and goes to your site
> - the first HTTP request that gets to Cocoon passes through the action
>   (like every other request, if the action is put around everything)
> - the action does its computation based on the user agent and sets one
>   or more sitemap parameters.  it also stores (caches) those parameters
>   in the session object.
> - the request goes on to the relevant matcher
> - if needed, any XSLT transformer (both XHTML- and SVG-producing ones)
>   can make choices based on the parameters set by the action and passed
>   to them by the pipeline
> - every subsequent request goes through the action, but unless the user
>   switches browser, or closes and reopens it, the action just reads the
>   cached parameters from the session object.
>
> I'm sure I'm missing something in your problem description, because this
> seems much easier to me than writing a custom Xalan extension!
>
>
> Toby
>
> --
> Signed/encrypted mail welcome.  GPG/PGP Key-Id: 0x15C5C2EA
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@cocoon.apache.org
> For additional commands, e-mail: users-help@cocoon.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@cocoon.apache.org
For additional commands, e-mail: users-help@cocoon.apache.org


Re: Parsing sitemap from within XSLT Transformer

Posted by Toby <to...@linux.it>.
Alain Pannetier wrote:
> Toby wrote:
> > you could put the action around everything, as the first and only
> > child of <map:pipelines>  [...] modify it so that it only computes
> > diagramType on the first request of every session, and then it just
> > returns a cached value.
> 
> This is actually what I started doing but then it finally dawned on me
> that a given document or a given pattern generating various document
> needs to cater for various types of SVG documents.

I don't understand your point very well.

You say that a document or a pattern needs to cater to various SVG
needs.  That's exactly why I suggested passing a parameter to the XSLT.

This is how I think it would work:
- the user opens the browser and goes to your site
- the first HTTP request that gets to Cocoon passes through the action
  (like every other request, if the action is put around everything)
- the action does its computation based on the user agent and sets one
  or more sitemap parameters.  it also stores (caches) those parameters
  in the session object.
- the request goes on to the relevant matcher
- if needed, any XSLT transformer (both XHTML- and SVG-producing ones)
  can make choices based on the parameters set by the action and passed
  to them by the pipeline
- every subsequent request goes through the action, but unless the user
  switches browser, or closes and reopens it, the action just reads the
  cached parameters from the session object.

I'm sure I'm missing something in your problem description, because this
seems much easier to me than writing a custom Xalan extension!


Toby

-- 
Signed/encrypted mail welcome.  GPG/PGP Key-Id: 0x15C5C2EA

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@cocoon.apache.org
For additional commands, e-mail: users-help@cocoon.apache.org


Re: Parsing sitemap from within XSLT Transformer

Posted by Alain Pannetier <al...@gmail.com>.
Hi Toby,

Thanks for your suggestion.
This is actually what I started doing but then it finally dawned on me
that a given document or a given pattern generating various document
needs to cater for various types of SVG documents.

There are various types of documents because SVG support is variable
across browsers.
Firefox for instance doesn't support filters.

So I cannot assume that a given document will emit all SVG embedded
pictures as vector or as bitmaps.

I've been working on this today and I'm nearly through.
I ended up implementing a Sitemap Xalan XSLT extension that
  - reads the sitemap
  - stores the pipelines matches
  - hijacks Cocoon's WildcardHelper class (I use only the wildcard matcher).
  - exposes a function that can predict under what form each distinct
SVG image will be sent.

This helps the stylesheet emitting the corresponding 'Tidy' XHTML.

I find this to be a cleaner solution than the other options I also had in mind.

Thanks to all.
Keep the suggestions coming in : I could always refactor things for a
better solution.

Alain Pannetier


On 8/18/06, Toby <to...@linux.it> wrote:
> Alain Pannetier wrote:
> > I am in a situation in which I need to know from within an XSLT
> > transformer what matcher will be selected for a given URL.
>
> I don't understand every detail of your setup, but I think you should
> run that diagram-format action on both the html and picture pipelines
> (or rather put the relevant matchers inside the action) so that you can
> pass the diagramType parameter to the stylesheet:
>
> <map:act type="diagram-format">
>   [svg_rule_* parameters...]
>
>   <map:match pattern="**/*somepattern*.svg">
>     [...]
>   </map:match>
>
>   <map:match pattern="*.html">
>     <!-- this generates the html that calls the diagram -->
>     [...]
>     <map:transform src="layout.xsl">
>       <map:parameter name="diagramType" value="{../diagramType}"/>
>     </map:transform>
>     [...]
>   </map:match>
> </map:act>
>
> Then just put a <xsl:param name="diagramType"/> at the top of your XSL
> and you can use it in any XSL test.
>
> Better yet, you could put the action around everything, as the first and
> only child of <map:pipelines>.  But then you'd better modify it so that
> it only computes diagramType on the first request of every session, and
> then just returns a cached value.
>
>
> Toby
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@cocoon.apache.org
> For additional commands, e-mail: users-help@cocoon.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@cocoon.apache.org
For additional commands, e-mail: users-help@cocoon.apache.org


Re: Parsing sitemap from within XSLT Transformer

Posted by Toby <to...@linux.it>.
Alain Pannetier wrote:
> I am in a situation in which I need to know from within an XSLT
> transformer what matcher will be selected for a given URL.

I don't understand every detail of your setup, but I think you should
run that diagram-format action on both the html and picture pipelines
(or rather put the relevant matchers inside the action) so that you can
pass the diagramType parameter to the stylesheet:

<map:act type="diagram-format">
  [svg_rule_* parameters...]
  
  <map:match pattern="**/*somepattern*.svg">
    [...]
  </map:match>

  <map:match pattern="*.html">  
    <!-- this generates the html that calls the diagram -->
    [...]
    <map:transform src="layout.xsl">
      <map:parameter name="diagramType" value="{../diagramType}"/>
    </map:transform>
    [...]
  </map:match>
</map:act>

Then just put a <xsl:param name="diagramType"/> at the top of your XSL
and you can use it in any XSL test.

Better yet, you could put the action around everything, as the first and
only child of <map:pipelines>.  But then you'd better modify it so that
it only computes diagramType on the first request of every session, and
then just returns a cached value.


Toby

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@cocoon.apache.org
For additional commands, e-mail: users-help@cocoon.apache.org