使用XSLT 2.0按里程碑元素连接文本节点

时间:2020-02-19 08:03:40

标签: xml xslt tei

我的XML文件具有TEI里程碑元素,例如<handShift new="#DP1053/><text>内容的开头总是有一个标签,但是此后有时会有一些这样的标签,其中两个或三个不同的属性值之一分散在<text>元素中,以指示最后一次之后,特别的抄写员回升。属性@new的值指向TEI标头中的@xml:id定义,并已注册为<handNote/>元素的属性。

我在XSLT 2.0中的目的是连接每个抄写员写的文本,以便我可以独立查询每个抄写员的工作。我想知道是否推荐的解决方案是否需要group-starting-with,但是我还没有把头放在所涉及的预处理上(我很感激指针)。相反,我的本能是表演

  • 一个for-each循环遍历抄写员的手,运行
  • 一个string-join
  • 在所有文本节点上
  • 其中属性<handShift/>的值与当前循环迭代中处理的手相匹配的前@new比前<handShift/>的属性值不匹配。

我在XSLT 2.0样式表中转换为HTML的试用语法如下:

<xsl:for-each select="//tei:handNote[@xml:id != '']">
    <xsl:variable name="hand" select="./@xml:id"/>
    <p><xsl:value-of select="$hand"/>: <xsl:value-of select="string-join(//tei:text//text()[preceding-sibling::tei:handShift[@new = concat('#',$hand)] &gt;&gt; preceding-sibling::tei:handShift[@new != concat('#',$hand)]])"/></p>
</xsl:for-each>

但是,这仅返回文本中最后一个里程碑之后的文本节点,并且仅在为与该最终里程碑匹配的属性值选择的for-each迭代中返回。我肯定会弄错>>语句,对于使用此方法或基于分组的其他方法提出的任何建议将不胜感激。

我可能应该提到,一旦我掌握了这种串联,就必须在方程式中添加任何<add hand="DP1054">addition</add>类型的内容(即,手动修改的内容与当前时间不匹配)。具有这种性质的不匹配内容,包括位于不匹配的抄写框内的匹配内容,但我不必预见必须将其添加到“正确”位置的串联中。因此,我应该能够通过两个相当简单的附加步骤来解决这些问题,但是初始的级联或分组解决方案必须允许排除属性值不匹配的节点以及我可能希望排除的其他任何元素(例如{ 1}})。

这是一个模拟XML文件:

<expan>

1 个答案:

答案 0 :(得分:0)

我认为“开始于组”会有所帮助,这是一个将结果存储在XPath 3.1映射中的示例(嗯,分组给出了一系列映射,map:merge函数将它们合并为一个映射从id到该id的handShift后的节点):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xpath-default-namespace="http://www.tei-c.org/ns/1.0"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:output method="html" indent="yes" html-version="5"/>

  <xsl:variable name="note-map-sequence" as="map(xs:string, node()*)*">
      <xsl:for-each-group select="//body/p/node()" group-starting-with="handShift">
          <xsl:map-entry key="substring(@new, 2)" select="current-group()"/>
      </xsl:for-each-group>
  </xsl:variable>

  <xsl:variable name="note-map" as="map(xs:string, node()*)"
    select="map:merge($note-map-sequence, map { 'duplicates' : 'combine' })"/>

  <xsl:template match="/">
    <html>
      <head>
        <title>.NET XSLT Fiddle Example</title>
      </head>
      <body>
        <xsl:apply-templates select="//handNote"/>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="handNote">
      <p>
        <xsl:value-of select="@xml:id"/>: 
        <xsl:apply-templates select="$note-map(@xml:id)"/>
      </p>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/bFWRApk具有在线示例输出

<!DOCTYPE HTML>
<html>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>.NET XSLT Fiddle Example</title></head>
   <body>
      <p>DP1054: 
         I'LL REPRESENT THE WORK OF HAND 1054 IN ALLCAPS THE IDEA BEING THAT IN THE END ALL UPPERCASE TEXT SHOULD BE CONCATENATED AND I WONDER WHETHER THESE WILL MESS WITH THE CONCEPT OF 
         SBLS
         SIBLINGS

      </p>
      <p>DP1053: 
         and I'll represent the work of hand 1053 in lowercase separately from the sentence case content. Of course reality is a little more COMPLEX: we have other nodes intervening,  (I will filter out nodes with `tei:expan` ancestors and nonmatching `add` elements;
         that's not the part I am having difficulty with).
      </p>
   </body>
</html>

自从Saxon 9.8开始提供带有XPath 3.1的XSLT 3,因此使用Saxon 9 for XSLT 2的大多数人也应该能够通过使用Saxon的最新(9.9)或以前的版本(9.8)来使用XSLT 3。

当然,地图仅用作分组结果的优雅且轻巧的容器,使用过的for-each-group也可以与XSLT 2一起使用,只需要将分组结果存储在某些中介中XML(例如<group id="{current-grouping-key()}">...</group>)。