使用 xsl:analyze-string 并保留标记(就像在身份转换中一样)

Use xsl:analyze-string and preserve markup (like in an identity transform)

我想处理一个 XML 文件,以便将连续两个换行符之前或之后的任何内容变成一个段落(就像在 LaTeX 中一样)。

这是源文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE letter SYSTEM "../Schema_and_DTD/entities.dtd">
<letter xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Schema_and_DTD/letter.xsd" page_id="940"title="1695-08-17_Faeh_Georg-Bernoulli_Johann_I" catalogue_id="000055848">

<facsimile src=""/> Colendissime ac ornatissime Domine etc.

Colendissimae dominationi Vestrae gratificandi ergo, exactissima diligentia tum in Bibliotheca nostra Conventuali, tum in Bibliopolio mihi commisso perquisivi Chronicon Joannis Vitodurani<ref><i>Die Chronik Johanns von Winterthur (Chronica Iohannis Vitodurani)</i>, herausgegeben von F. Baethgen und C. Brun in: <i>Scriptores rerum Germanicarum</i>, Nova series 3, Berlin 1924.</ref>, sed nihil de eo repertum fuit.<ref>Leibniz hat die Chronik des Johannes von Winterthur später aus Bremen erhalten und in seinem <i>Codex juris gentium diplomaticus</i>, Hanoverae 1693, abgedruckt.</ref> Hisce post mei recommendationem omnem prosperitatem a Bono Deo intime apprecans sum et ero Ornatissimae vestrae dominationis Addictissimus servus P. Georgius Fäch.

Ex Eremo B. V. M.<ref>Einsiedeln</ref> 17. Augusti Anno 1695.

</letter>

我找到了这个解决方案:XSLT - add <p> into text strings instead of \n

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>

<xsl:template match="letter">

    <xsl:analyze-string select="." regex="&#xa;&#xa;">
            <xsl:non-matching-substring>
                <p>
                    <xsl:value-of select="." disable-output-escaping="yes" />
                </p>
            </xsl:non-matching-substring>
        </xsl:analyze-string>

</xsl:template>

这已经接近我想要的,但问题是 <xsl:value-of select="." disable-output-escaping="yes" /> 没有保留任何标记。最后,我只有包含文本内容的段落标签(所有标签都被删除了)。

我想到了身份转换,但不允许我使用 <xsl:apply-templates /> 而不是 <xsl:value-of select=".">

我要制作的是这样的:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE letter SYSTEM "../Schema_and_DTD/entities.dtd">
<letter xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Schema_and_DTD/letter.xsd" page_id="940" title="1695-08-17_Faeh_Georg-Bernoulli_Johann_I" catalogue_id="000055848">

<p><facsimile src=""/> Colendissime ac ornatissime Domine etc.</p>

<p>Colendissimae dominationi Vestrae gratificandi ergo, exactissima diligentia tum in Bibliotheca nostra Conventuali, tum in Bibliopolio mihi commisso perquisivi Chronicon Joannis Vitodurani<ref><i>Die Chronik Johanns von Winterthur (Chronica Iohannis Vitodurani)</i>, herausgegeben von F. Baethgen und C. Brun in: <i>Scriptores rerum Germanicarum</i>, Nova series 3, Berlin 1924.</ref>, sed nihil de eo repertum fuit.<ref>Leibniz hat die Chronik des Johannes von Winterthur später aus Bremen erhalten und in seinem <i>Codex juris gentium diplomaticus</i>, Hanoverae 1693, abgedruckt.</ref> Hisce post mei recommendationem omnem prosperitatem a Bono Deo intime apprecans sum et ero Ornatissimae vestrae dominationis Addictissimus servus P. Georgius Fäch.</p>

<p>Ex Eremo B. V. M.<ref>Einsiedeln</ref> 17. Augusti Anno 1695.</p>

</letter>  

有没有办法获取整个不匹配的子字符串(包括标记)并用段落标记将其包裹起来?

我认为你需要两次通过,一次插入某个元素(我选择了 br 但当然你可以选择任何不会干扰你现有词汇的东西),第二次使用 for-each-group group-starting-with="br":

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:output indent="yes"/>

    <xsl:template match="@*|node()" mode="#all">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" mode="#current"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="letter">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:variable name="letter-with-line-breaks">
                <xsl:apply-templates select="." mode="breaks"/>
            </xsl:variable>
            <xsl:for-each-group select="$letter-with-line-breaks/letter/node()" group-starting-with="br">
                <p>
                    <xsl:apply-templates select="current-group()[not(self::br)]"/>
                </p>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="letter//text()" mode="breaks">
        <xsl:analyze-string select="." regex="&#10;&#10;">
          <xsl:matching-substring>
              <br/>
          </xsl:matching-substring>
          <xsl:non-matching-substring>
              <xsl:value-of select="."/>
          </xsl:non-matching-substring>
        </xsl:analyze-string>
    </xsl:template>
</xsl:transform>

这应该会给你一个想法,我认为你需要一些白色的 space 调整。

这个问题有两种解决方法。

一种是在文本中添加标记,然后使用分组等工具来处理标记指示的结构:这就是 Martin 使用的方法。

第二种方法是将现有标记转换为某种文本注释,然后使用分析字符串来处理文本,然后将文本注释转换回标记。

对于 XSLT 3.0,第二种方法可以通过将 <p> 元素的内容序列化为字符串(使用 fn:serialize()),然后应用 xsl:analyze-string,然后解析使用 fn:parse-xml().

将结果返回到树中的节点