[xsl] XSL-FO block organization - grouping problem

Subject: [xsl] XSL-FO block organization - grouping problem
From: "Kyle Partridge" <kpartridge@xxxxxxxxxxxx>
Date: Fri, 26 Mar 2004 16:20:40 -0500
Experts,

I have read Jeni Tennison's articles on grouping, and I'm still not sure
how to proceed with this.

I've got some XML that looks like this ( just a short example, there are
many, many regions in the document ):

<regions>
<region region-id="53" left="36" top="296.25" width="42.75" height="12">
	<text>
	<p style="Normal" margin-left="inherit" margin-right="inherit"
text-indent="inherit" text-align="inherit" list-style-type="inherit"
tabs="inherit">Definition:</p>
	</text>
</region>
<region region-id="52" left="120" top="295.5" width="36" height="14.25">
	<math optimize="false" export="false" disable-calc="false">
		<ml:define xmlns:ml="urn:schemas-mathsoft-com:mcml">
			<ml:id>i</ml:id>
			<ml:apply>
				<ml:sqrt/>
				<ml:real>-1</ml:real>
			</ml:apply>
		</ml:define>
	</math>
	<rendering item-idref="8"/>
</region> 
</regions>

I have been trying to produce XSL-FO that will allow me to specify these
two regions as belonging within the same horizontal area.  Roughly, I
want to see:

Definition:  <math>

The region containing the "Definition" text has a slightly lower "top"
coordinate than the region containing the math does.  So, I thought,
maybe I could just do everything as an inline, and "pad" the top of the
inline containing the "Definition" text, like this:

<fo:block space-before="22.5pt" start-indent="36pt" space-after="0pt"
end-indent="283pt" line-strategy="max-height">
	<fo:block-container absolute-position="auto" margin-left="0pt"
margin-right="0pt" text-indent="0pt" text-align="left">
		<fo:block>
			<fo:inline padding-before="0.75pt"
font-family="Arial,Helvetica,sans-serif" font-size="10pt"
font-weight="normal" font-style="normal">Definition:</fo:inline>
			<fo:leader width="59.25pt"/>
			<fo:external-graphic src="url(8.jpg)" />
		</fo:block>
	</fo:block-container>
</fo:block>

That *seems* to produce the output I want.  So, the problem becomes how
to isolate ALL the regions which will be inlines within one block, like
these two are.

If a region is in a block area by itself, it is easy to render.  but if
I come across something that needs to look like this:

	------  
	|    |  ------------
	| 1  |  |          |
      ------  |          |
              |     2    |
              |          |
    ------    |          |
    |  3 |    ------------
    ------

it seems like the only way to do it is to put them all in one block, and
then put them each in an inline, and pad around and in between those
inlines. But it's really difficult to get the "block-like" down-flow
within the larger areas.

Two questions, then:  

Is there another way to do this, using inline-containers?  I tried to
use them, but because each inline container must contain a block, I
couldn't figure out how to control them being next to each other, or
overlapping within a horizontal area.  I kept getting this:

Definition:
            <math>

which wasn't what I wanted.


I'm going through a tremendous rigamarole to get the set of regions
which belong within the containing block.

<!-- part of a template... -->
<xsl:variable name="this-beside-next">
	<xsl:call-template name="beside">
		<xsl:with-param name="region1" select="."/>
		<xsl:with-param name="region2"
select="$col-regions[position()=$current-position+1]"/>
	</xsl:call-template>
</xsl:variable>			
<xsl:choose>
	<xsl:when test="boolean($this-beside-next)">
		<xsl:apply-templates select="."
mode="horizontal-region-block">
			<xsl:with-param name="following-regions"
select="$col-regions[position()&gt;=$current-position]"/>
			<xsl:with-param name="prev-region"
select="$col-regions[postion()=$current-position-1]"/>
		</xsl:apply-templates>
	</xsl:when>
	<xsl:otherwise>..some other code here..</xsl:otherwise>
</xsl:choose>
<!-- end partial template code -->

	
<xsl:template name="beside">
	<!-- Determine whether or not region1 and region2 are next to
each other -->
	<xsl:param name="region1"/>
	<xsl:param name="region2"/>
	<xsl:variable name="one-covers-two">
		<xsl:call-template name="in-shadow-of">
			<xsl:with-param name="region1"
select="$region1"/>
			<xsl:with-param name="region2"
select="$region2"/>
		</xsl:call-template>
	</xsl:variable>
		
	<xsl:choose>
		<xsl:when test="$one-covers-two=1">1</xsl:when>
		<xsl:otherwise>
			<xsl:variable name="two-covers-one">
				<xsl:call-template name="in-shadow-of">
					<xsl:with-param name="region1"
select="$region2"/>
					<xsl:with-param name="region2"
select="$region1"/>
				</xsl:call-template>
			</xsl:variable>
			<xsl:choose>
				<xsl:when
test="$two-covers-one=1">1</xsl:when>
				<xsl:otherwise>0</xsl:otherwise>
			</xsl:choose>
		</xsl:otherwise>
	</xsl:choose>
</xsl:template>

	
<xsl:template match="ws:region" mode="horizontal-region-block">
		<xsl:param name="following-regions"/>
		<xsl:param name="prev-region"/>
		<xsl:variable name="next-region"
select="$following-regions[1]"/>
		<xsl:variable name="bottom">
			<xsl:call-template
name="calculate-region-bottom">
				<xsl:with-param name="region"
select="."/>
			</xsl:call-template>
		</xsl:variable>
		<xsl:variable name="right">
			<xsl:call-template
name="calculate-region-right">
				<xsl:with-param name="region"
select="."/>
			</xsl:call-template>
		</xsl:variable>
		<xsl:variable name="temp-block-set">
			<region-data region-id="{@region-id}"
left="{@left}" top="{@top}" right="{$right}" bottom="{$bottom}"/>
			<xsl:for-each select="$following-regions">
				<xsl:variable name="current-position"
select="position()"/>
				<xsl:variable name="beside-next">
					<xsl:call-template
name="beside">
						<xsl:with-param
name="region1" select="."/>
						<xsl:with-param
name="region2"
select="$following-regions[position()=$current-position+1]"/>
					</xsl:call-template>
				</xsl:variable>
				<xsl:choose>
					<xsl:when test="$beside-next=1">
						<xsl:variable
name="this-bottom">
	
<xsl:call-template name="calculate-region-bottom">
	
<xsl:with-param name="region" select="."/>
	
</xsl:call-template>
						</xsl:variable>
						<xsl:variable
name="this-right">
	
<xsl:call-template name="calculate-region-right">
	
<xsl:with-param name="region" select="."/>
	
</xsl:call-template>
						</xsl:variable>
						<region-data
region-id="{@region-id}" left="{@left}" top="{@top}"
right="{$this-right}" bottom="{$this-bottom}"/>
					</xsl:when>
					<xsl:when test="$beside-next=0">
						<region-data id="stop"/>
					</xsl:when>
				</xsl:choose>
			</xsl:for-each>
		</xsl:variable>
		<xsl:variable name="stop-node"
select="position($temp-block-set/region-data[@region-id='stop'])"/>
		<xsl:variable name="horizontal-block-set">
			<xsl:copy-of
select="$temp-block-set[position()&lt;$stop-node]"/>
		</xsl:variable>
		
		<xsl:variable name="space-before">
			<xsl:call-template
name="get-space-before-setblock">
				<xsl:with-param name="region-set"
select="$horizontal-block-set"/>
				<xsl:with-param name="prev-region"
select="$prev-region"/>
			</xsl:call-template>
		</xsl:variable>
				
		<xsl:variable name="space-after">
			<xsl:choose>
				<xsl:when
test="$horizontal-block-set/region-data[position() = last()]/@region-id
= $following-regions/region-data[position() = last()]/@region-id">
					<xsl:call-template
name="get-space-after-last-setblock">
						<xsl:with-param
name="region-set" select="$horizontal-block-set"/>
					</xsl:call-template>
				</xsl:when>
				<xsl:otherwise>0</xsl:otherwise>
			</xsl:choose>
		</xsl:variable>
						
		<xsl:variable name="start-indent">
			<xsl:call-template
name="get-setblock-start-indent">
				<xsl:with-param name="region-set"
select="$horizontal-block-set"/>
			</xsl:call-template>
		</xsl:variable>
					
		<xsl:variable name="end-indent">
			<xsl:call-template
name="get-setblock-end-indent">
				<xsl:with-param name="region-set"
select="$horizontal-block-set"/>
			</xsl:call-template>				
		</xsl:variable>
					
		<xsl:call-template name="create-region-setblock">
			<xsl:with-param name="space-before"
select="$space-before"/>
			<xsl:with-param name="space-after"
select="$space-after"/>
			<xsl:with-param name="start-indent"
select="$start-indent"/>
			<xsl:with-param name="end-indent"
select="$end-indent"/>
			<xsl:with-param name="region-set"
select="$horizontal-block-set"/>
			<xsl:with-param name="next-region"
select="$next-region"/>
		</xsl:call-template>

	</xsl:template>

Current Thread