You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XML转XML-FO生成PDF:xsl:choose仅匹配首个元素的问题排查

解决XSLT处理多语言<name>元素的问题

我正在用XSLT把XML转换成XML-FO来生成PDF,表格是3列布局,前4行的第2、3列处于合并状态。但现在遇到个问题:处理<names>节点下的多个<name>元素时,只能匹配到第一个,第二个<name>完全无法被正确处理。

我的XML结构

<WS-Standards> 
  <tags> 
    <tag category = "parameters" > 
      <!-- WS_Beer_Type -->
      <tag_name>WS_Beer_TypeX</tag_name> 
      <!-- browsename -->
      <tag_number>30004</tag_number> 
      <datatype>Unsigned32</datatype> 
      <accessrights>RW</accessrights> 
      <names> 
        <name language="DE">Biersorte</name> 
        <name language="EN">Beer Type</name> 
      </names> 
    </tag> 
  </tags> 
</WS-Standards>

当前使用的XSLT(部分截断)

<?xml version="1.0" encoding="UTF-8" ?> 
<xsl:stylesheet version="1.0" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
  <xsl:output method="xml" version="1.0" indent="yes"/> 
  <xsl:template match="WS-Standards"> 
    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> 
      <fo:layout-master-set> 
        <fo:simple-page-master page-height="297mm" page-width="210mm" margin="5mm 25mm 5mm 25mm" master-name="PageMaster"> 
          <fo:region-body margin="20mm 0mm 20mm 0mm"/> 
        </fo:simple-page-master> 
      </fo:layout-master-set> 
      <fo:page-sequence master-reference="PageMaster"> 
        <fo:flow flow-name="xsl-region-body"> 
          <fo:block> 
            <xsl:apply-templates select="tags"/> 
          </fo:block> 
        </fo:flow> 
      </fo:page-sequence> 
    </fo:root> 
  </xsl:template> 
  <xsl:template match="tags"> 
    <fo:block> 
      <xsl:apply-templates select="tag"/> 
    </fo:block> 
  </xsl:template> 
  <xsl:template match="tag"> 
    <fo:block space-before="6pt" border-top="3pt solid green"> 
      <fo:table> 
        <fo:table-column column-number="1" column-width="20%" border-style="solid" border-width="1pt"/> 
        <fo:table-column column-number="2" column-width="10%" border-style="solid" border-width="1pt"/> 
        <fo:table-column column-number="3" column-width="70%" border-style="solid" border-width="1pt"/> 
        <fo:table-body> 
          <xsl:apply-templates/> 
        </fo:table-body> 
      </fo:table> 
    </fo:block> 
  </xsl:template> 
  <xsl:template match="tag_name"> 
    <fo:table-row> 
      <fo:table-cell column-number="1" border="1pt solid black"> 
        <fo:block> Tag Name </fo:block> 
      </fo:table-cell> 
      <fo:table-cell column-number="2" number-columns-spanned="2" border="1pt solid black"> 
        <fo:block> 
          <xsl:value-of select="."/> 
        </fo:block> 
      </fo:table-cell> 
    </fo:table-row> 
  </xsl:template> 
  <xsl:template match="tag_number"> 
    <fo:table-row> 
      <fo:table-cell column-number="1" border="1pt solid black"> 
        <fo:block> Tag-Nummer </fo:block> 
      </fo:table-cell> 
      <fo:table-cell column-number="2" number-columns-spanned="2" border="1pt solid black"> 
        <fo:block> 
          <xsl:value-of select="."/> 
        </fo:block> 
      </fo:table-cell> 
    </fo:table-row> 
  </xsl:template> 
  <xsl:template match="datatype"> 
    <fo:table-row> 
      <fo:table-cell column-number="1" border="1pt solid black"> 
        <fo:block> Datentyp </fo:block> 
      </fo:table-cell> 
      <fo:table-cell column-number="2" number-columns-spanned="2" border="1pt solid black"> 
        <fo:block> 
          <xsl:value-of select="."/> 
        </fo:block> 
      </fo:table-cell> 
    </fo:table-row> 
  </xsl:template> 
  <xsl:template match="accessrights"> 
    <fo:table-row> 
      <fo:table-cell column-number="1" border="1pt solid black"> 
        <fo:block> Zugriffsrechte </fo:block> 
      </fo:table-cell> 
      <fo:table-cell column-number="2" number-columns-spanned="2" border="1pt solid black"> 
        <fo:block> 
          <xsl:value-of select="."/> 
        </fo:block> 
      </fo:table-cell> 
    </fo:table-row> 
  </xsl:template> 
  <xsl:template match="names"> 
    <xsl:choose> 
      <xsl:when test="number(./name/position()) = 1"> 
        <fo:table-row> 
          <fo:table-cell column-number="1" border="1pt solid black"> 
            <fo:block> Name </fo:block> 
          </fo:table-cell> 
          <fo:table-cell column-number="2" border="1pt solid black"> 
            <fo:block> 
              <xsl:value-of select="./name/@language"/> 
            </fo:block> 
          </fo:table-cell> 
          <fo:table-cell column-number="3" border="1pt solid black"> 
            <fo:block> 
              <xsl:value-of select="./name"/> 
            </fo:block> 
          </fo:table-cell> 
        </fo:table-row> 
      </xsl:when> 
      <xsl:otherwise> 
        <fo:table-row> 
          <fo:table-cell column-number="1" border="1pt solid black"> 
            <fo:block> NameXXX </fo:block> 
          </fo:table-cell> 
          <fo:table-cell column-number="2" border="1pt 

问题分析

你之前的写法核心问题在于:直接匹配<names>节点后,用<xsl:choose>判断第一个<name>的位置,但<names>节点本身只会被处理一次,没法遍历内部的多个<name>元素。而且./name/position()这种写法返回的是整个<name>集合的位置(永远为1),所以只会触发<xsl:when>的逻辑,完全处理不到第二个<name>。

解决方案

把匹配<names>的模板改成遍历每个<name>元素,在遍历过程中判断是否是第一个元素,只在第一行显示“Name”,后续行的第一列留空即可。修改后的模板代码如下:

<xsl:template match="names">
  <!-- 遍历每个name元素 -->
  <xsl:for-each select="name">
    <fo:table-row>
      <fo:table-cell column-number="1" border="1pt solid black">
        <fo:block>
          <!-- 只有第一个name元素显示"Name",其余留空 -->
          <xsl:if test="position() = 1">Name</xsl:if>
        </fo:block>
      </fo:table-cell>
      <fo:table-cell column-number="2" border="1pt solid black">
        <fo:block>
          <xsl:value-of select="@language"/>
        </fo:block>
      </fo:table-cell>
      <fo:table-cell column-number="3" border="1pt solid black">
        <fo:block>
          <xsl:value-of select="."/>
        </fo:block>
      </fo:table-cell>
    </fo:table-row>
  </xsl:for-each>
</xsl:template>

这样修改后,每个<name>元素都会生成一行表格:第一行第一列显示“Name”,第二行第一列空着,两行分别展示DE和EN的语言标签及对应名称,完美解决你之前的问题。另外注意你原来的XSLT代码末尾有截断,记得把模板标签都闭合完整哦。

内容的提问来源于stack exchange,提问作者Christoph

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:55:02