xsl-list
[Top] [All Lists]

Re: [xsl] Formatting issues

2007-01-02 14:46:06
ms wrote:
Hi:
Thank you for all your help.

Tell me, did it help? What did you try and what worked, and what did not work?


Here is the sample XML:

Thanks

My sample XSLfo:

This appeared being XSLT, not xsl-fo. However, it does produce xsl-fo. I'd have liked a less verbose version, with all the not-necessary things removed. Doing so, will likely increase your chances to responses. I did the cleanup myself. See my comments about the content (I tried to make the xml/xslt readable in the mail).


   <fo:block>
      <xsl:apply-templates select="test"/>
   </fo:block>
        
<xsl:template match="test">
   <fo:block>
       <xsl:apply-templates/>
   </fo:block>
</xsl:template>

This pair adds nothing to your logic (and a nested block doesn't either). A single <xsl:apply-templates /> would've sufficed.


   <xsl:template match="level1">
      <xsl:choose>
         <xsl:when test=".//locn">
            <xsl:if test=".//locn/cond1=$val1 and
                          .//locn/cond2=$val2">

This looks to me as a very dangerous construct (and potentially very resource intensive). What you say in the test-clause is "search the whole tree from here and look for a "locn" node. Search again all the "locn" nodes from the current child and from all you find, check its "cond1 and cond2" node and compare its value with the value in $val1 and $val2, if there's a match, it is true. In short: whatever the depth of "cond1" and "cond2" nodes, if any matches $val1 and $val2, it is true. I can hardly imagine that this is your intend (on XSLT 2 this comparison works differently and will likely always fail).

I am not sure of what you want to accomplish here. At least you can remove the double test, which adds nothing:

<xsl:when test=".//locn/cond1=$val1 and
               .//locn/cond2=$val2">


And if the logic you want is: "if any of the conditions of the current level1 matches $val1 and $val2, output the complete tree from here. If not, do not output the tree, you should write it as follows:

<xsl:when test="locn/cond1=$val1 and
               locn/cond2=$val2">


which tests if any cond1 node equals $val1 and if any cond2 node equals $val2. If you only want to match the first such nodes, it becomes as follows:

<xsl:when test="locn[1]/cond1[1]=$val1 and
               locn[1]/cond2[1]=$val2">

And be aware of evil whitespace:
<xsl:when test="normalize-space(locn[1]/cond1[1])
               = normalize-space($val1) ....


        
<xsl:otherwise>
   <xsl:call-template name="level">
       <xsl:with-param name="format">1</xsl:with-param>
   </xsl:call-template>
</xsl:otherwise>

This "xsl:otherwise" is never called. However, I assume in your original code this has a purpose? You mean to apply a different numbering when there is no locn node whatsoever somewhere down the tree?



<xsl:template match="level2">

You are really going to repeat the same logic again? Why didn't you try to apply my approach here with the substring matches? This makes your code extremely unreadable and unmaintainable.

<xsl:choose>
   <xsl:when test=".//locn">
   <xsl:if test=".//locn/cond1=$val1 and
                 .//locn/cond2=$val2">

Here you apply exactly the same tests as above. It is recommended, in any language, to repeat as little as possible. This logic should all go into the same template match (this way you'll have to copy it for every level!).

<xsl:number format="A"/>

This appears to me as the only difference per level. I recommend using a lookup table or something for this kind of thing.


<xsl:otherwise>
   <xsl:call-template name="level">
       <xsl:with-param name="format">a</xsl:with-param>
   </xsl:call-template>
</xsl:otherwise>

This, again, is never called.

<xsl:template name="level">

This named template is never called.

<xsl:choose>
   <xsl:when test="$format = '1'">
      <xsl:number format="1"/>.</fo:inline>

This kind of structure is a waste of space and makes it hard for you to maintain the whole thing. Remove the xsl:choose and write it like this, as a single statement:

<xsl:number format="{$format}"/>

Which does precisely what you want: output in the format you supply.





Now val1 and val 2 are high and deep. So the expected
output is:
2 This level should be displayed only if the
conditions are high and deep.

Which will never happen, see my comments above.

However, instead of 2, it should be numbered 1 since
it is the first level.

Again (and still) I am stuck. You want all numbers on one level numbered the same? Than you do not need a numbering scheme. Your input data is way to vague to make it understandable: all texts are equal and you do not make any effort in clearly distinguishing what should go where. In your posts, levels are not indented and the subject is too complex to understand from three lines.

In addition, you fail to answer my primary question: how and with what indentation should a certain input be displayed and what condition must be met to restart numbering (if it is indeed about numbering, it looks now as if every number should start with 1?). I'd like to help, but you really should make your subject clear.


Desired output on the PDF would be:

1. This level should be displayed only if the
conditions are high and deep.

From this I reckon you only want one level to be output? Consider the suggested changes for your main xsl:choose.

I asked you this before, and now I will do so again: take the message of a poster, and go through it and add your comments so that you don't leave unanswered any question he/she asks.

In addition: please try to apply the former replies to your query. They seem (as far as I can tell) to contain the resolution. To help you apply that logic, here's a quick and dirty hack that aims to output what you want: starting numbering based on the condition. Also, it applies some of the tips I gave above. Please look it through carefully and try to apply it. It is likely not all you want, but for that, you really have to be clearer and try to apply the solutions first. I used the translate() function to make the levels a bit easier, however, if you prefer, you can make the variable a chain of xsl:if statements. Remove the conditionality on the count-attribute and the select-attribute to see the whole tree build based on the levels of the input. It outputs, using your XML, the following having more L1 items in the main node, will increment the number):

1. This level should be displayed only if the
conditions are high and deep.




<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
   xmlns:fo="http://www.w3.org/1999/XSL/Format";>
<xsl:output indent="yes"/> <xsl:variable name="val1">high</xsl:variable>
   <xsl:variable name="val2">deep</xsl:variable>
<xsl:template match="root/test">
       <fo:root
           xmlns:fo="http://www.w3.org/1999/XSL/Format";>
           <fo:layout-master-set>
               <fo:simple-page-master master-name="cover">
                   <fo:region-body
                       region-name="coverPage-region-body"
                       margin="18mm" />
               </fo:simple-page-master>
           </fo:layout-master-set>
           <fo:page-sequence master-reference="cover">
               <fo:flow flow-name="coverPage-region-body">
                   <fo:block>
<!-- content -->
                       <xsl:apply-templates select="
                           *[starts-with(name(.), 'level')]
                           [locn/cond1=$val1 and locn/cond2=$val2]"/>
                   </fo:block>
               </fo:flow>
           </fo:page-sequence>
       </fo:root>
   </xsl:template>
<xsl:template match="
       *[starts-with(name(.), 'level')]">
<xsl:variable name="level" select="substring(name(.), 6,1)" />
       <xsl:variable name="format" select="
concat(translate(substring(name(.), 6,1), '1234567', '1aAIi11'),
           translate(substring(name(.), 6,1), '1234567', ' ).).).'))" />
<fo:list-block space-before="6pt"
           space-before.conditionality="retain">
           <fo:list-item>
               <fo:list-item-label end-indent="label-end()">
                   <fo:block>
                       <xsl:number
                           format="{$format}"
                           level="single"
                           count="
                               *[substring(name(.), 6, 1) = $level]
                               [locn/cond1=$val1 and locn/cond2=$val2]"/>
</fo:block>
               </fo:list-item-label>
               <fo:list-item-body start-indent="body-start()"
                   end-indent="0pt">
                   <fo:block>
                       <xsl:apply-templates />
                   </fo:block>
               </fo:list-item-body>
           </fo:list-item>
       </fo:list-block>
   </xsl:template>
</xsl:stylesheet>




Cheers,
-- Abel Braaksma
  http://www.nuntia.nl

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--

<Prev in Thread] Current Thread [Next in Thread>