在 xslt 中使用正则表达式来操作元素的文本,同时保持对子节点及其属性的处理(使用 TEI 样式表配置文件)

use regex in xslt to manipulate text of element while maintain processing of child nodes and their attributes (using TEI stylesheets profile)

我目前正在为 TEI xslt 样式表 (https://tei-c.org/release/doc/tei-xsl/) 编写配置文件,以自定义从 MSword docx 格式到符合 TEI XML 的转换(并进一步转换为有效 HTML).在我的例子中,我需要定制的一个特定转换是我有一堆文本引用特定的视频源档案。在文本中,这些引用类似于 [box: 001 roll: 01 start: 00:01:00.00]。我想使用正则表达式查找这些引用并在 tei:figure 元素中生成符合 TEI 的 tei:media 元素。当参考文献在其自己的段落中时,这很有效。但是不同的作者在他们的文本段落中有引用(元素 tei:p)。这里开始挑战,因为这些 pragraphs 可能包含其他元素,如 tei:note 或 tei:hi,应该保持完整并充分处理。不幸的是,xslt 指令 xsl:analyze-string 创建子字符串,因此您不能对它们使用 xsl:apply-templates,只能使用 xsl:copy-of。这适用于 xsl:matching-substring 但 xsl:non-matching-substring 包含如上所述的一些其他应处理的元素(具有属性)。

TEI 样式表转换相当复杂,并且 运行 各种传递。在我想干预我的个人资料的阶段,我的段落已经有一个 tei 元素 p。 例如:

<p>This is my paragraph with a note <note place="foot">This is my note</note> and it is <hi rend="italic">important</hi> that this inline elements and their attributes are kept and further processed. This is my special reference to a video in the archive [box: 001 roll: 01 start: 00:01:10.12] that should be transformed into a valid tei:media element.</p>

到目前为止我的转变(简化):

 <xsl:template match="tei:p" mode="pass2">
  <xsl:choose>
   <xsl:when test=".,'\[[Bb]ox:.+?\]'">
    <xsl:analyze-string select="." regex="\[box: (\d+) roll: (\d+) start: ((\d\d):(\d\d):(\d\d).(\d\d))\]">
     <xsl:matching-substring>
      <xsl:element name="ref">
       <xsl:attribute name="target">
        <xsl:value-of select="concat('https://path-to-video-page/',regex-group(1),'-',regex-group(2),'/',regex-group(4),'-'regex-group(5),'-',regex-group(6),'-',regex-group(7))"/>
       </xsl:attribute>
       <xsl:value-of select="concat('(box: ',regex-group(1),' roll: ',regex-group(2),' @ ',regex-group(4),'h 'regex-group(5),'m ',regex-group(6),'s)')"/>
      </xsl:element>
      
      <figure place="margin">
       <xsl:element name="head">
        <xsl:value-of select="concat('Sequence from box: ',regex-group(1),' roll: ',regex-group(2))"/>
       </xsl:element>
       <xsl:element name="media">
        <xsl:attribute name="mimeType">video/mp4</xsl:attribute>
         <xsl:attribute name="url">
          <xsl:value-of select="concat('https://path-to-video/',regex-group(1),'-',regex-group(2),'.mp4')"/>
         </xsl:attribute>
         <xsl:attribute name="start">
           <xsl:value-of select="regex-group(3)"/>
         </xsl:attribute>
       </xsl:element>
      </figure>
     </xsl:matching-substring>
     <xsl:non-matching-substring>
      <xsl:copy-of select="."/>
     </xsl:non-matching-substring>
    </xsl:analyze-string>  
   <xsl:otherwise>
    <xsl:apply-templates mode="pass2"/>
   </xsl:otherwise>
  </xsl:choose>
  </p>
 </xsl:template>

结果:

<p>This is my paragraph with a note This is my note and it is important that this inline elements and their attributes are kept and further processed. This is my special reference to a video in the archive <ref target="https://path-to-video-page/001-01/00-01-10-12">(box: 001 roll: 01 @ 00h 01m 10s)</ref>
<figure rend="margin">
   <head rend="none">Sequence from box: 001 roll: 01</head>
   <media mimeType="video/mp4" url="path-to-video/001-01.mp4" start="00:01:10.12"/>
</figure> that should be transformed into a valid tei:media element.</p>

现在我卡住了。是否可以用正则表达式操作p元素中文本的匹配内容,同时维护不匹配部分的“节点字符”以供进一步处理?还是我走入了死胡同,应该为此停止与 xml 混在一起?我正在考虑的替代方案是将引用作为文本保留在 xml 中,并使用 python 脚本 post 处理生成的 xml/html 文件。但如果可能的话,在 xslt 中做所有事情会更优雅。

感谢任何建议 奥拉夫

解决方法很简单:将模板匹配改为

xsl:template match="tei:p//text()"

当应用于 tei:p 时,xsl:analyze-string 将整个元素分解为可以使用正则表达式解析的字符串。仅匹配文本节点 tei:p//text() 会保留 tei:p 及其 parent/ancestor/sibling 元素的其余元素结构。 xsl:analyze-string 然后只对文本进行操作,其余部分由其他模板或默认身份转换处理。

许多xsl:analyze-string的教程或示例将其应用于整个元素,因为他们只想提取一些信息以进行进一步处理,而将原始元素留在后面。如果您想使用 xsl:analyze-string 更改您进一步用作元素的元素的文本,则必须仅将其应用于文本节点。

感谢@Martin Honnen 在对我的问题的评论中提出的建议。