【问题标题】:XSLT 2 - convert single characters to processing-instructionXSLT 2 - 将单个字符转换为处理指令
【发布时间】:2022-10-20 10:23:50
【问题描述】:

我有一个文本节点,其中包含 7 位 ASCII 文本以及更高的 unicode 字符(例如 x2011、xF0B7、x25CF ...)

我需要能够(有效地)将这些单个高 unicode 字符转换为处理指令

例如

&#x2011;  ->   <processing-instruction name="xxx">character output="hyphen"</pro...>
&#xF0B7;  ->   <processing-instruction name="xxx">character output="page"</pro...>

我试过使用xsl:tokenize,它确实在第一个标记分隔符(例如x2011)之前/之后分割文本,但我最终得到一个包含'text...&lt;processing-instruction&gt;...&lt;/processing-instruction'...text'的变量,它会触发下一个xsl:token

我设法采用了以下方法来工作,但它看起来真的很不优雅,我确信有一种更有效/更好的方法可以做到这一点,但我还没有找到任何有效或更好的方法。

第一个字符替换很容易,使用replace(),因为我只是转义%(目标软件使用'%' 来表示其他东西,所以需要以这种方式转义)。

是的,这适用于 x2011-to-< ... >,但最初的目的是直接转换为处理指令。

    <xsl:template match="text()">
        <xsl:variable name="SR1">
            <xsl:value-of select="fn:replace(., '%', '\\%')"/>
        </xsl:variable>
        <!-- unbreakable hyphen -->
        <xsl:variable name="SR2">
            <xsl:call-template name="tokenize">
                <xsl:with-param name="string" select="$SR1"/>
                <xsl:with-param name="delimiter">&#x2011;</xsl:with-param>
                <xsl:with-param name="PI"><xsl:text>&lt;?xpp character symbol="bxhyphen" hex="x2011" data="E28091"?&gt;</xsl:text></xsl:with-param>
            </xsl:call-template>
        </xsl:variable>
        <!-- page ref -->
        <xsl:variable name="SR3">
            <xsl:call-template name="tokenize">
                <xsl:with-param name="string" ><xsl:copy-of select="$SR2"/></xsl:with-param>
                <xsl:with-param name="delimiter">&#xF0B7;</xsl:with-param>
                <xsl:with-param name="PI"><xsl:text>&lt;?xpp character symbol="pgref" hex="xF0B7" data="EF82B7"?&gt;</xsl:text>
                </xsl:with-param>
            </xsl:call-template>
        </xsl:variable>
        <!-- page ref -->
        <xsl:variable name="SR4">
            <xsl:call-template name="tokenize">
                <xsl:with-param name="string" ><xsl:copy-of select="$SR3"/></xsl:with-param>
                <xsl:with-param name="delimiter">&#x25CF;</xsl:with-param>
                <xsl:with-param name="PI"><xsl:text>&lt;?xpp character symbol="bub" hex="x25CF" data="E2978F"?&gt;</xsl:text>
                </xsl:with-param>
            </xsl:call-template>
        </xsl:variable>
        <xsl:copy-of select="$SR4"/>
    </xsl:template>

理想情况下,我的目标是有一个“对”列表、十六进制 unicode 及其匹配的处理指令,但任何更好的解决方案将不胜感激!

另一个功能是标记尚未处理的字符,因此 x00-x1F、xFF+ 范围内的任何字符(不包括 x2011、x25CF xF0B7)。

【问题讨论】:

  • 如果您想处理文本以创建节点,那么使用 XSLT 2/3 xsl:analyze-string(或在 XSLT 3 中的 analyze-string 函数)通常是可行的方法。结果中的处理指令通常使用xsl:processing-instruction 创建,不清楚为什么使用一些xsl:text
  • 另外,xsl:token 是什么?某些 XSLT 扩展的一部分?
  • 哎呀。应该是 xsl:tokenize ;)
  • 在早期版本中,我确实使用了适用于第一个字符的分析字符串(例如 x2011)。我有:``` <xsl:variable name="SR2"> <xsl:analyze-string select="$SR1" regex="^(.*)‑(.*)$"> <xsl:匹配子字符串> <xsl:value-of select="regex-group(1)"/> <xsl:processing-instruction> ... </processing-instruction> <xsl:value-of select="regex-group (2)"/> </xsl:analyze-string> </xsl:variable> ``` 但是当我用同样的方法定义$SR3,在analyze-string/select中调用$SR2时,却没有' t 输出 $SR2 中包含的处理指令。

标签: xml xslt xslt-2.0 invisible-xml


【解决方案1】:

如果您要查找的字符是已知且有限的,我会列出它们,例如&lt;xsl:template match="text()"&gt;&lt;xsl:analyze-string select="." regex="&amp;#x2011;&amp;#xF0B7;&amp;#x25CF;"&gt;&lt;xsl:matching-substring&gt;&lt;xsl:processing-instruction name="xxp" select="mf:map(.)"/&gt;&lt;/xsl:matching-substring&gt;&lt;xsl:non-matching-substring&gt;&lt;xsl:value-of select="."/&gt;&lt;/xsl:non-matching-substring&gt;&lt;/xsl:analyze-string&gt;&lt;/xsl:template&gt; 其中mf:map 是您设置的一个函数,它将每个字符映射到您想要作为 pi 数据输出的字符串。在 XSLT 3 中,我可能会将字符到名称的映射存储在 XPath/XSLT 映射中,在 XSLT 2 中,您可以使用一些 xsl:paramxsl:variable,例如&lt;xsl:param name="characters-to-name"&gt;&lt;map char="&amp;#x2011;"&gt;bxhyphen&lt;/map&gt;...&lt;/xsl:param&gt; 并在需要时选择它,甚至通过设置一个键。

XSLT/XPath/XQuery 领域的全新是最近发布的不可见 XML 规范 (https://invisiblexml.org/),它具有各种(尚未完善)实现;使用不可见的 XML,您可以为您的格式定义一个语法,然后处理器只使用该语法将其转换为 XML,您可以像往常一样使用 XSLT/XPath/XQuery 进行处理。

因此,使用例如语法

text: (ascii | hyphen | page | bub)*.
-ascii: ["a"-"z"; "A"-"Z"; "0"-"9"].
hyphen: #2011.
page: #F0B7.
bub: #25CF.

不可见的 XML 处理器将转换输入,例如A‑B 到 XML &lt;text&gt;A&lt;hyphen&gt;‑&lt;/hyphen&gt;B&lt;/text&gt; 中,然后您可以使用 XSLT 进一步处理以创建任何专用输出,例如,您想要的处理指令。

【讨论】:

  • 我将代码修改为:<xsl:analyze-string select="." regex="(%|‑||●)"> <xsl:matching-substring> <xsl:variable name="rg1" select="fn:regex-group(1) "/> <xsl:processing-instruction name="xpp" select="$charmap/character[@key=$rg1]"/> </xsl:matching-substring> ... and <xsl:variable name=" charmap"> <character key="‑">bxhyphen</character> 这个(非常轻微的)修改版本很有效,比我的原始代码快得多 - 并且更容易添加新字符,因为它们使自己变得明显.谢谢你
【解决方案2】:

没有xsl:analyze-string 的版本如下。它使用一个单独的文件来存储代码点/字符串关系。

因此,在此示例中,名为 codes.xml 的文件包含映射(必须先将十六进制值转换为十进制 - 这里已经完成):

<CharKey>
    <Char cp="8209"  string="hyphen" />
    <Char cp="61623" string="page" />
</CharKey>

并且样式表(这里是 XSLT-3.0,但它也可以与 XSLT-2.0 一起使用,并进行一些小的修改)迭代字符串的代码点:

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="yes"/>    
    <xsl:variable name="codes" select="document('codes.xml')/CharKey" />
    <!-- text() node is matched here -->   
    <xsl:template match="/Record/Text">
        <xsl:variable name="cps" select="string-to-codepoints(.)" />
        <xsl:for-each select="$cps">
            <xsl:variable name="curCP" select="$codes/Char[@cp=current()]" />
            <xsl:choose>
                <xsl:when test="$curCP"><xsl:processing-instruction name="xxx" expand-text="yes">character output="{$curCP/@string}"</xsl:processing-instruction></xsl:when>
                <xsl:otherwise><xsl:value-of select="codepoints-to-string(.)" /></xsl:otherwise>
            </xsl:choose>                
        </xsl:for-each>
    </xsl:template>
    
</xsl:stylesheet>

这可以进一步简化,但作为一个例子,它应该可以工作。
样品的

<Record>
    <Text>Hello&#x2011;&#xF0B7;End</Text>
</Record>

输出是

Hello<?xxx character output="hyphen"?><?xxx character output="page"?>End

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-30
    • 1970-01-01
    • 1970-01-01
    • 2013-02-09
    • 1970-01-01
    相关资源
    最近更新 更多