转义序列的XML转换

时间:2014-11-28 12:18:47

标签: xml xslt

我有以下XML。我想使用XSL-FO将其转换为在<escape V=".br"/>处添加换行符,并在<escape V="H"/><escape V="N"/>之间加粗文本。有什么建议?即使是XML-&gt; html示例也足够了。

<OBX.5>
                Tan<escape V=".br"/>MB BS FRACS PhD<escape
                        V=".br"/>Hospital &amp; Specialist Centre<escape
                        V=".br"/>Address:<escape
                        V=".br"/>XX XX Street<escape
                        V=".br"/>XXX<escape
                        V=".br"/>HUTT 5011<escape
                        V=".br"/>Date of Birth:<escape
                        V=".br"/>15.03.1987<escape
                        V=".br"/>Telephone:<escape
                        V=".br"/>(h) 9888 26846<escape
                        V=".br"/>(m) 0221 632 4590<escape
                        V=".br"/>HI Number:<escape
                        V=".br"/>JAP5065<escape V=".br"/>
    <escape V=".br"/>
                    After the 5 dots is a Bolded Line.....<escape
                        V="H"/> TEST Escape Characters<escape V="N"/>TEST more
    <escape V=".br"/>
</OBX.5>

1 个答案:

答案 0 :(得分:1)

这样可行,但显式不表示嵌套格式(即粗体+斜体):

<xsl:template match="OBX.5">
  <fo:block linefeed-treatment="preserve">
    <xsl:apply-templates select="node()[
      count(preceding-sibling::escape[@V = 'H']) 
      - count(preceding-sibling::escape[@V = 'N'])
      = 0
    ]" />
  </fo:block>
</xsl:template>

<!-- add a line break where there is <escape V=".br"/> -->
<xsl:template match="escape[@V = '.br']">
  <xsl:text>&#xA;</xsl:text>
</xsl:template>

<!-- bold the text between <escape V="H"/> and <escape V="N"/> -->
<xsl:template match="escape[@V = 'H']">
  <fo:inline font-weight="bold">
    <xsl:apply-templates select="
      following-sibling::escape[@V = 'N'][1]/preceding-sibling::node()[
        generate-id(preceding-sibling::escape[@V = 'H'][1]) = generate-id(current())
      ]
    " />
  </fo:inline>
</xsl:template>

<!-- all other escapes are ignored -->
<xsl:template match="escape" />

<!-- trim all text nodes before output (optional, remove if unnecessary) -->
<xsl:template match="text()">
  <xsl:value-of select="normalize-space()" />
</xsl:template>

样品的输出:

<block xmlns="http://www.w3.org/1999/XSL/Format" linefeed-treatment="preserve">Tan
MB BS FRACS PhD
Hospital &amp; Specialist Centre
Address:
XX XX Street
XXX
HUTT 5011
Date of Birth:
15.03.1987
Telephone:
(h) 9888 26846
(m) 0221 632 4590
HI Number:
JAP5065

After the 5 dots is a Bolded Line.....<inline font-weight="bold">TEST Escape Characters</inline>TEST more
</block>

请注意,只有escape[@V = '.br']实际上会创建一个换行符,所以&#34;在5个点之后是一个粗线......&#34; 不能为真你的意见。


我使用的XPath表达式需要一些解释,所以这里是。

想象一下<OBX.5>的孩子作为这个列表:

 # Node                                     H   N  H-N 
-------------------------------------------------------
 1 Tan                                      0   0   0
 2 <escape V=".br"/>                        0   0   0
 3 MB BS FRACS PhD                          0   0   0
   ... and so on ...                        .   .   .
29 <escape V=".br"/>                        0   0   0
30 After the 5 dots is a Bolded Line.....   0   0   0
31 <escape V="H"/>                          0   0   0
32 TEST Escape Characters                   1   0   1
33 <escape V="N"/>                          1   0   1
34 TEST more                                1   1   0
35 <escape V=".br"/>                        1   1   0

,其中

  • Hcount(preceding-sibling::escape[@V = 'H'])
  • Ncount(preceding-sibling::escape[@V = 'N'])
  • H-N显然是两者的区别。

所以用

<xsl:apply-templates select="node()[
  count(preceding-sibling::escape[@V = 'H']) 
  - count(preceding-sibling::escape[@V = 'N'])
  = 0
]" />

我们处理 #32#33以外的所有节点

模板#3对#31进行特殊处理,渲染一个包含以下内容的粗体容器:

<xsl:apply-templates select="
  following-sibling::escape[@V = 'N'][1]/preceding-sibling::node()[
    generate-id(preceding-sibling::escape[@V = 'H'][1]) = generate-id(current())
  ]
" />

XPath转换为

  • 转到第一个escape[@V = 'N']
  • 从那里
  • ,向后看(preceding-sibling)并选择
  • 所有节点
  • 前一个escape[@V = 'H']的ID与当前escape[@V = 'H']的ID相同。

此条件仅适用于您示例中的#32#33,实际上它会以一种方式切片节点列表,以防止将更多文本呈现为粗体而非所需。

节点#33被模板#4丢弃,我们只需将它用于计数目的。