复制文本并替换 XSL 中的字符
Copy text and replace character in XSL
我正在将 DITA 文档转换为基于格式的简化 XML 以用作导入到 Adobe InDesign 中。我的转换进行得非常顺利,除了一个元素在输出中省略了文本。该元素是 codeblock
。当我根本没有指定它的模板时,元素和任何子元素都会传递到新的 XML 文档,但会传递文本的 none。此元素应与文本 和 子元素一起传递,就像我的文档中未定义特定模板的所有其他元素一样。 XSL 样式表中没有任何其他地方指定 codeblock
或其任何属性。我完全被难住了,无法弄清楚这里发生了什么。
还值得注意的是,许多内联元素(cmdname
、parmname
、userinput
等)在输出时被转换为 bold
。下游XML用于格式化,不需要知道语义上下文。
这就是我要通过的内容:
<codeblock>This is the first line of my code block.
This is my second line to prove that line feeds are preserved.
This line proves that <parmname>child elements</parmname> are passed through.</codeblock>
没有为 codeblock
定义模板,这就是我得到的结果:
<codeblock><bold/></codeblock>
我想要的实际结果是:
<codeblock>This is the first line of my code block.
This is my second line to prove that line feeds are preserved.
This line proves that <bold>child elements</bold> are passed through.</codeblock>
我需要用字符实体替换换行符,因为 InDesign 会将任何不以元素开头的新行视为分栏符。我的目标是使用以下模板简单地用 

替换换行符:
<xsl:template match="codeblock//text()">
<xsl:analyze-string select="." regex="( )">
<xsl:matching-substring>
<xsl:choose>
<xsl:when test="regex-group(1)">
</xsl:when>
</xsl:choose>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:template>
但我得到的是:
<codeblock>
<bold/>
</codeblock>
我终于可以使用这个模板传递文本了:
<xsl:template match="codeblock//text()">
<xsl:copy/>
</xsl:template>
成功!顺便说一下,我必须在代码块下的任何级别进行匹配,因此它也包括子 parmname 元素的文本。由于我能够使用 <xsl:copy>
成功传递它,因此我尝试在替换换行符的同时传递文本:
<xsl:template match="codeblock//text()">
<xsl:copy>
<xsl:analyze-string select="." regex="( )">
<xsl:matching-substring>
<xsl:choose>
<xsl:when test="regex-group(1)">
</xsl:when>
</xsl:choose>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:copy>
</xsl:template>
但现在它不会取代新的换行符。相反,我得到了这个(这是我希望在没有定义任何模板的情况下得到的):
<codeblock>This is the first line of my code block.
This is my second line to prove that line feeds are preserved.
This line proves that <bold>child elements</bold> are passed through.</codeblock>
我知道这是一个很长而且有点令人费解的问题。我只是觉得如果我能首先解决为什么它不传递文本的问题,剩下的就相当简单了。很抱歉,我无法提供我的来源 XML 或 XSL,因为它处于 NDA 之下,但如果您需要更多,请告诉我,我会尽力提供。 (我的 XSL 样式表由 12 个不同的文件组成,所以我无法提供所有文件,即使是通用化的。)
关于我可能在我的样式表中寻找的内容的任何建议,这些建议可以解释为什么文本会出现,或者任何关于如何强制它通过的建议,就像我对 <xsl:copy>
所做的那样,同时仍然替换换行符将非常感谢!
编辑添加: 我想到它没有进行替换的原因是它看起来实际上不是换行符。它更像是代码中的新行,而不是文本中的换行符(或硬 return)。我想我可能需要在每行末尾插入 

字符时规范化文本。仍在调查中,但欢迎提出建议!
编辑更新: 感谢 post How to detect line breaks in XSLT,我已经接近了,但仍然不是我需要的地方。使用此代码,我能够检测 XML 中的换行符并为 InDesign 插入换行符:
<xsl:template match="codeblock//text()">
<xsl:for-each select="tokenize(., '\n?')[.]">
<xsl:sequence select="."/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
但是,它还会在字符串末尾插入换行符,即使它不是行尾也是如此。例如,我现在得到:
<codeblock>This is the first line of my code block.
This is my second line to prove that line feeds are preserved.
This line proves that 
<bold>child elements
</bold> are passed through.
</codeblock>
我不想在 'bold' 开始和结束标记或 codeblock
结束标记前使用换行符。我只是想让它出现在有实际换行的地方。我尝试替换 \r
但只是忽略了新行并将其放在标签前面。有谁知道另一个可以在这里使用的转义字符?
一个非常长的问题 - 但仍然不清楚你到底在问什么(也没有可重现的例子)。
如果 - 看起来 - 你想在 codeblock
元素下的所有文本节点中用行分隔符替换换行符,你应该能够简单地做到:
<xsl:template match="codeblock//text()">
<xsl:value-of select="translate(., ' ', '
')" />
</xsl:template>
如果这不起作用,则要么您有一个覆盖模板,要么文本不包含换行符。您可以通过更改模板来测试第一种情况:
<xsl:template match="codeblock//text()">BINGO</xsl:template>
并观察结果是否所有目标文本节点都更改为“BINGO”。要测试第二种情况,您可以使用 string-to-codepoints()
函数逐个字符地分析文本。
您的模板缺少 xsl:non-matching-substring
来处理文本节点的不匹配部分。
<xsl:template match="codeblock//text()">
<xsl:analyze-string select="." regex="\n">
<xsl:matching-substring>
<xsl:text>
</xsl:text>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
但是, 更简单,因为您不需要 xsl:analyze-string
来替换所有子字符串。
我正在将 DITA 文档转换为基于格式的简化 XML 以用作导入到 Adobe InDesign 中。我的转换进行得非常顺利,除了一个元素在输出中省略了文本。该元素是 codeblock
。当我根本没有指定它的模板时,元素和任何子元素都会传递到新的 XML 文档,但会传递文本的 none。此元素应与文本 和 子元素一起传递,就像我的文档中未定义特定模板的所有其他元素一样。 XSL 样式表中没有任何其他地方指定 codeblock
或其任何属性。我完全被难住了,无法弄清楚这里发生了什么。
还值得注意的是,许多内联元素(cmdname
、parmname
、userinput
等)在输出时被转换为 bold
。下游XML用于格式化,不需要知道语义上下文。
这就是我要通过的内容:
<codeblock>This is the first line of my code block.
This is my second line to prove that line feeds are preserved.
This line proves that <parmname>child elements</parmname> are passed through.</codeblock>
没有为 codeblock
定义模板,这就是我得到的结果:
<codeblock><bold/></codeblock>
我想要的实际结果是:
<codeblock>This is the first line of my code block.
This is my second line to prove that line feeds are preserved.
This line proves that <bold>child elements</bold> are passed through.</codeblock>
我需要用字符实体替换换行符,因为 InDesign 会将任何不以元素开头的新行视为分栏符。我的目标是使用以下模板简单地用 

替换换行符:
<xsl:template match="codeblock//text()">
<xsl:analyze-string select="." regex="( )">
<xsl:matching-substring>
<xsl:choose>
<xsl:when test="regex-group(1)">
</xsl:when>
</xsl:choose>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:template>
但我得到的是:
<codeblock>
<bold/>
</codeblock>
我终于可以使用这个模板传递文本了:
<xsl:template match="codeblock//text()">
<xsl:copy/>
</xsl:template>
成功!顺便说一下,我必须在代码块下的任何级别进行匹配,因此它也包括子 parmname 元素的文本。由于我能够使用 <xsl:copy>
成功传递它,因此我尝试在替换换行符的同时传递文本:
<xsl:template match="codeblock//text()">
<xsl:copy>
<xsl:analyze-string select="." regex="( )">
<xsl:matching-substring>
<xsl:choose>
<xsl:when test="regex-group(1)">
</xsl:when>
</xsl:choose>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:copy>
</xsl:template>
但现在它不会取代新的换行符。相反,我得到了这个(这是我希望在没有定义任何模板的情况下得到的):
<codeblock>This is the first line of my code block.
This is my second line to prove that line feeds are preserved.
This line proves that <bold>child elements</bold> are passed through.</codeblock>
我知道这是一个很长而且有点令人费解的问题。我只是觉得如果我能首先解决为什么它不传递文本的问题,剩下的就相当简单了。很抱歉,我无法提供我的来源 XML 或 XSL,因为它处于 NDA 之下,但如果您需要更多,请告诉我,我会尽力提供。 (我的 XSL 样式表由 12 个不同的文件组成,所以我无法提供所有文件,即使是通用化的。)
关于我可能在我的样式表中寻找的内容的任何建议,这些建议可以解释为什么文本会出现,或者任何关于如何强制它通过的建议,就像我对 <xsl:copy>
所做的那样,同时仍然替换换行符将非常感谢!
编辑添加: 我想到它没有进行替换的原因是它看起来实际上不是换行符。它更像是代码中的新行,而不是文本中的换行符(或硬 return)。我想我可能需要在每行末尾插入 

字符时规范化文本。仍在调查中,但欢迎提出建议!
编辑更新: 感谢 post How to detect line breaks in XSLT,我已经接近了,但仍然不是我需要的地方。使用此代码,我能够检测 XML 中的换行符并为 InDesign 插入换行符:
<xsl:template match="codeblock//text()">
<xsl:for-each select="tokenize(., '\n?')[.]">
<xsl:sequence select="."/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
但是,它还会在字符串末尾插入换行符,即使它不是行尾也是如此。例如,我现在得到:
<codeblock>This is the first line of my code block.
This is my second line to prove that line feeds are preserved.
This line proves that 
<bold>child elements
</bold> are passed through.
</codeblock>
我不想在 'bold' 开始和结束标记或 codeblock
结束标记前使用换行符。我只是想让它出现在有实际换行的地方。我尝试替换 \r
但只是忽略了新行并将其放在标签前面。有谁知道另一个可以在这里使用的转义字符?
一个非常长的问题 - 但仍然不清楚你到底在问什么(也没有可重现的例子)。
如果 - 看起来 - 你想在 codeblock
元素下的所有文本节点中用行分隔符替换换行符,你应该能够简单地做到:
<xsl:template match="codeblock//text()">
<xsl:value-of select="translate(., ' ', '
')" />
</xsl:template>
如果这不起作用,则要么您有一个覆盖模板,要么文本不包含换行符。您可以通过更改模板来测试第一种情况:
<xsl:template match="codeblock//text()">BINGO</xsl:template>
并观察结果是否所有目标文本节点都更改为“BINGO”。要测试第二种情况,您可以使用 string-to-codepoints()
函数逐个字符地分析文本。
您的模板缺少 xsl:non-matching-substring
来处理文本节点的不匹配部分。
<xsl:template match="codeblock//text()">
<xsl:analyze-string select="." regex="\n">
<xsl:matching-substring>
<xsl:text>
</xsl:text>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
但是,xsl:analyze-string
来替换所有子字符串。