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>
--~--