【问题标题】:XSLT FO program, XML data structuring issue into PDFXSLT FO 程序,将 XML 数据结构化问题转换为 PDF
【发布时间】:2020-10-28 06:16:54
【问题描述】:

我是 XSLT 的新手,需要将 XML 文件转换为 PDF。我有一个使用 XSLT FO 文件将 XML 转换为 PDF 的 JAVA 程序。

下面是我的 XML。

<PDFReport xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Type>ABC</Type>
<Number>001</Number>
<CustomerDetails>
  <Country>USA</Country>
  <Name>John Doe</Name>
</CustomerDetails>
<PurchasedGoods>Category A</PurchasedGoods>
<Amount>123456</Amount>
<CustomerDetails>
  <Country>China</Country>
  <Name>Stuart Lim</Name>
</CustomerDetails>
<PurchasedGoods>Category B</PurchasedGoods>
<Amount>987654</Amount>
</PDFReport>

我正在使用下面的 XSLT 文件转换为 XML 文件

<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 method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/">
    <fo:root>
        <fo:layout-master-set>
            <fo:simple-page-master master-name="simple" margin="0.5in">
                <fo:region-body/>
              </fo:simple-page-master>
        </fo:layout-master-set>
        <fo:page-sequence master-reference="simple">
            <fo:flow flow-name="xsl-region-body">
                <xsl:apply-templates/>
            </fo:flow>
        </fo:page-sequence>
    </fo:root>
</xsl:template>

<xsl:template match="PDFReport">
    <xsl:apply-templates select="./Type"/> 
    <xsl:apply-templates select="./Number"/> 
    <xsl:for-each select="./CustomerDetails">        
           <xsl:apply-templates select="."/>   
    </xsl:for-each>
    <xsl:apply-templates select="./PurchasedGoods"/> 
    <xsl:apply-templates select="./Amount"/> 
</xsl:template>

<xsl:template match="Type">
    <fo:block text-align="left" font-family="Arial">
         <fo:block>Type :  <xsl:value-of select="."/></fo:block>
    </fo:block>  
</xsl:template>
<xsl:template match="Number">
    <fo:block text-align="left" font-family="Arial">
         <fo:block>Number :  <xsl:value-of select="."/></fo:block>
    </fo:block>  
</xsl:template>
<xsl:template match="Country">
    <fo:block text-align="left" font-family="Arial">
         <fo:block>Country :  <xsl:value-of select="."/></fo:block>
    </fo:block>  
</xsl:template>
<xsl:template match="Name">
    <fo:block text-align="left" font-family="Arial">
         <fo:block>Name :  <xsl:value-of select="."/></fo:block>
    </fo:block>  
</xsl:template>
<xsl:template match="PurchasedGoods">
    <fo:block text-align="left" font-family="Arial">
         <fo:block>Purchased Goods :  <xsl:value-of select="."/></fo:block>
    </fo:block>  
</xsl:template>
<xsl:template match="Amount">
    <fo:block text-align="left" font-family="Arial">
         <fo:block>Amount :  <xsl:value-of select="."/></fo:block>
    </fo:block>  
 </xsl:template>
 </xsl:stylesheet>

我得到的 PDF 输出如下

Type : ABC
Number : 001
Country : USA
Name : John Doe
Country : China
Name : Stuart Lim
Purchased Goods : Category A
Purchased Goods : Category B
Amount : 123456
Amount : 987654

但是,我想要输出如下。

Type : ABC
Number : 001

Country : USA
Name : John Doe
Purchased Goods : Category A
Amount : 123456

Country : China
Name : Stuart Lim
Purchased Goods : Category B
Amount : 987654

在不改变XML结构的情况下可以做到以上几点。

谢谢

【问题讨论】:

    标签: java xml xslt xsl-fo


    【解决方案1】:

    您正在获得当前结果,因为您指示元素按照xsl:apply-templates 序列中的顺序处理:

    <xsl:template match="PDFReport">
        <xsl:apply-templates select="./Type"/> 
        <xsl:apply-templates select="./Number"/> 
        <xsl:for-each select="./CustomerDetails">        
               <xsl:apply-templates select="."/>   
        </xsl:for-each>
        <xsl:apply-templates select="./PurchasedGoods"/> 
        <xsl:apply-templates select="./Amount"/> 
    </xsl:template>
    

    首先,您可以让源文档的结构定义处理元素的顺序,只需删除PDFReport 的模板即可。

    在 XSLT 中,只需 &lt;xsl:apply-templates /&gt;(如您的模板中的 \)选择所有子节点并将模板应用到它们。不同节点类型的内置默认模板的效果意味着,在样式表中没有模板的元素节点只需在其子节点上执行&lt;xsl:apply-templates /&gt;,而不会自己向结果中添加任何内容。使用内置的默认模板,只有文本节点最终被复制到结果树中。可以说,删除PDFReport 的模板将导致TypeNumberCustomerDetails 等按照它们在源文档中出现的顺序进行处理。

    其次,要在客户详细信息之前留出一些空间,请为CustomerDetails 添加一个模板,其中包含一个指定space-before 值的fo:block(请参阅https://www.w3.org/TR/xsl11/#space-before):

    <xsl:template match="CustomerDetails">
      <fo:block space-before="1em">
        <xsl:apply-templates />
      </fo:block>
    </xsl:template>
    

    这个&lt;xsl:apply-templates /&gt; 将按文档顺序处理CustomerDetails 的子节点。 (在您展示的样式表中没有CustomerDetails 的模板,反正就是这样。)

    或者,如果Country 始终是CustomerDetails 的第一个孩子,您可以只在fo:block 上为Country 指定space-before

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-17
      相关资源
      最近更新 更多