Выровняйте данные XML по правому краю при создании PDF с помощью fo: list-block

У меня есть список номеров в моем вводе XML, и я могу выровнять тело списка (текстовое содержимое) по правому краю, но числа остаются выровненными по левому краю. Как я могу выровнять весь список, включая числа / маркеры, по правому краю, по умолчанию идет слева. Любая помощь или указатели приветствуются, спасибо.

Токовый выход:

 Number list below
 1.                                                                 L List 1
 2.                                                                 R list 2

Мой ожидаемый результат:

 Number list below
                                                                   1. L List 1
                                                                   2. R list 2

Я упростил XML-данные, как показано ниже:

<p>Number list below</p>
      <ol>
         <li style="text-align: right;">L list 1</li>
         <li style="text-align: right;">R list 2</li>
      </ol>

Мой код xslt выглядит так:

<xsl:template match="LI|li">
	<fo:list-block>	
		<xsl:attribute name="text-align">
			<!--xsl:value-of select="end"/-->
			<xsl:text disable-output-escaping="yes">right</xsl:text>
		</xsl:attribute>		
		<fo:list-item>
			<fo:list-item-label end-indent="label-end()">
				<fo:block>
					<xsl:variable name="value-fetcher">
						<xsl:choose>
							<xsl:when test="../@start">
								<xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI)+ ../@start"/>
							</xsl:when>
							<xsl:otherwise>
								<xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI) + 1"/>
							</xsl:otherwise>
						</xsl:choose>
					</xsl:variable>
					<xsl:number value="$value-fetcher" format="1."/>					
				</fo:block>
			</fo:list-item-label>
			<fo:list-item-body start-indent="body-start()">			
				<fo:block>
					<xsl:apply-templates select="text()"/>
				</fo:block>
			</fo:list-item-body>				
		</fo:list-item>
	</fo:list-block>
</xsl:template>


person Ashu    schedule 02.12.2017    source источник


Ответы (3)


Мне кажется, что выровненный по правому краю список переменной ширины - не совсем то, для чего был разработан fo:list-block.

Предполагая, что ваш форматтер FO реализует fo:table-and-caption, вы можете создать таблицу, которая будет выглядеть так, как вы хотите:

  <table-and-caption text-align="right">
    <table text-align="left">
      <table-body>
        <table-row>
          <table-cell padding="1pt">
            <block>1.</block>
          </table-cell>
          <table-cell padding="1pt">
            <block>L List 1</block>
          </table-cell>
        </table-row>
      </table-body>
      <table-body>
        <table-row>
          <table-cell padding="1pt">
            <block>2.</block>
          </table-cell>
          <table-cell padding="1pt">
            <block>R list 2</block>
          </table-cell>
        </table-row>
      </table-body>
    </table>
  </table-and-caption>

При отсутствии fo:table-and-caption вы можете злоупотреблять fo:block-container и свойством writing-mode:

  <block-container writing-mode="rl">
    <table text-align="left" writing-mode="lr">

или вы можете использовать fo:leader (https://www.w3.org/TR/xsl11/#fo_leader), чтобы "протолкнуть" fo:inline-container (https://www.w3.org/TR/xsl11/#fo_inline-container) справа:

  <block>
    <leader leader-length.optimum="100%"/><inline-container>
    <table>
person Tony Graham    schedule 04.12.2017
comment
Спасибо за ответ, fo: table-and-caption еще не поддерживается. Есть ли другой способ добиться такого форматирования. - person Ashu; 04.12.2017

С вашим шаблоном есть несколько проблем:

  • вы не устанавливаете provisional-distance-between-starts, который вместе с _ 2_ определяет ширину метки элемента, поэтому вы получаете ширину 24pt - 6pt = 18pt
  • на этикетках ваших товаров отсутствует необходимый end-indent="label-end()", а тела элементов отсутствуют start-indent="body-start()", поэтому они не имеют правильного размера / положения.

Этот измененный шаблон должен работать:

<xsl:template match="LI|li">
    <fo:list-block text-align="end" provisional-distance-between-starts="3cm"><!-- set the value you want! -->  
        <fo:list-item>
            <fo:list-item-label end-indent="label-end()">
                <fo:block>
                    <xsl:variable name="value-fetcher">
                        <xsl:choose>
                            <xsl:when test="../@start">
                                <xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI)+ ../@start"/>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI) + 1"/>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:variable>
                    <xsl:number value="$value-fetcher" format="1."/>                    
                </fo:block>
            </fo:list-item-label>
            <fo:list-item-body start-indent="body-start()">         
                <fo:block>
                    <xsl:apply-templates select="text()"/>
                </fo:block>
            </fo:list-item-body>                
        </fo:list-item>
    </fo:list-block>
</xsl:template>

Небольшая придирка: вы создаете fo:list-block для каждого li элемента ввода, в то время как вы можете создать только один для каждого ol или ul.


Поскольку вы заранее не знаете ширину, которую нужно зарезервировать для метки, но это зависит от самого текста элемента ... ну, может быть, вам вообще не нужно использовать fo:list-block!

Выровненного по правому краю fo:block должно быть достаточно, при условии, что текст элемента всегда создает только одну строку:

<xsl:template match="LI|li">
    <fo:block text-align="end"> 
        <fo:inline>
            <xsl:variable name="value-fetcher">
                <xsl:choose>
                    <xsl:when test="../@start">
                        <xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI)+ ../@start"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI) + 1"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:variable>
            <xsl:number value="$value-fetcher" format="1."/>                    
        </fo:inline> 
        <fo:inline>
            <xsl:apply-templates select="text()"/>
        </fo:inline>
    </fo:block>
</xsl:template>
person lfurini    schedule 02.12.2017
comment
Спасибо за ответ, я могу получить ожидаемый результат для образца ввода, установив предварительное расстояние между запусками = 14 см, но это не всегда так при увеличении размера строки списка, который он перекрывает. Можно ли рассчитать временное расстояние между запусками динамически на основе размера строки или ширины страницы. - person Ashu; 02.12.2017
comment
В основном мой размер строки будет меняться в зависимости от введенного пользователем текста. Спасибо. - person Ashu; 02.12.2017
comment
Ответ обновлен: если вводимый пользователем текст занимает всего одну строку, это еще проще! - person lfurini; 02.12.2017

Спасибо за ответы, всегда полезно.

выравнивание достигается ниже xslt:

<xsl:template match="LI|li">
<fo:block margin-left="36pt" text-align="right">
	<fo:leader leader-pattern="space" leader-length="-18pt"/>
	<fo:inline><xsl:variable name="value-fetcher">
                        <xsl:choose>
                            <xsl:when test="../@start">
                                <xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI)+ ../@start"/>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI) + 1"/>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:variable>
                    <xsl:number value="$value-fetcher" format="1."/> 
	</fo:inline>
	<fo:inline>
	<fo:leader leader-pattern="space" leader-length="18pt"/>
	 <xsl:apply-templates select="text()"/>
	</fo:inline>
</fo:block>
</xsl:template>

person Ashu    schedule 12.12.2017