查找使用正则表达式混合XML内容(Finding mixed XML content with re

2019-10-17 03:04发布

在我的XSLT 2.0样式表的运行,我需要找到某些文本(例如,“故事3.1”,“故事8.19”,“21.76故事”),并用它做的东西(例如,包装在一个超链接)。 发现这些情况,做我想要什么和他们是简单的任务。 我虽然碰到的问题是,有时候我可能需要被包裹在超链接混合内容(例如,“故事3.1 <I>在</ I>”)。 我已经无法弄清楚如何做到这一点。

下面是一些样本数据和我的模板:

<p>Jack goes up the hill (story 3.1<i>a</i>) to fetch a pail of water.</p>

<xsl:template match="text()">
<xsl:variable name="content" as="xs:string" select="."/>
<xsl:analyze-string select="$content" regex="Story [0-9]*\.[0-9]*" flags="i">
  <xsl:matching-substring>
    <xsl:variable name="figureToTargetId">
      <xsl:analyze-string select="." regex="[0-9]*\.[0-9]*">
        <xsl:matching-substring>
          <xsl:value-of select="concat('s',.)"/>
        </xsl:matching-substring>
      </xsl:analyze-string>
    </xsl:variable>
    <a href="#{$figureToTargetId}"><xsl:value-of select="."/></a>        
  </xsl:matching-substring>
  <xsl:non-matching-substring><xsl:value-of select="."/>
  </xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>

另外,在上述情况下,我会希望“故事3.1 <I>一</ i>的”被包裹在该超链接。

我知道这个问题,才能获得理想的我不得不匹配文本以外的东西()。 我不知道那是什么,但。

一种方法我一直在探索通过文本节点集使用XSL循环:对,每测试一个文本节点是否只有一个字母字符长。 如果是的话,把它包在同一个超链接的以前的文本节点。 (由于种种原因,我知道,一个文本节点后,上面的章恩匹配任何一个字母字符长的文本节点应超链接到同一目标)。但是我希望有一个更好的解决方案。

Answer 1:

这一转变

<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="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="p/text()[matches(., 'Story [0-9]+(\.[0-9]+)')]">
    <xsl:variable name="vCur" select="."/>
    <xsl:variable name="pContent" select="string(.)"/>
    <xsl:analyze-string select="$pContent" regex="Story [0-9]*\.[0-9]*" flags="i">
      <xsl:matching-substring>
        <xsl:variable name="figureToTargetId">
          <xsl:analyze-string select="." regex="[0-9]*\.[0-9]*">
            <xsl:matching-substring>
              <xsl:value-of select="concat('s',.)"/>
            </xsl:matching-substring>
          </xsl:analyze-string>
        </xsl:variable>
        <a href="#{$figureToTargetId}">
         <xsl:value-of select="."/>
         <xsl:if test="not(matches($vCur, 'Story [0-9]+(\.[0-9]+).+$'))">
          <xsl:sequence select="$vCur/following-sibling::*[1]"/>
         </xsl:if>
        </a>
      </xsl:matching-substring>
      <xsl:non-matching-substring><xsl:value-of select="."/></xsl:non-matching-substring>
    </xsl:analyze-string>
 </xsl:template>
 <xsl:template match=
  "p/*[preceding-sibling::node()[1]
         [self::text()
        and
          matches(., 'Story [0-9]+(\.[0-9]+)$')]
         ]"/>
</xsl:stylesheet>

当这个文档上施加 (提供的一个扩展为包含两个有趣的情况):

<t>
    <p>Little Red Riding Hood (Story 3.1) </p>
    <p>Jack goes up the hill (Story 3.1<i>a</i>) to fetch a pail of water.</p>
</t>

产生想要的,正确的结果

<t>
      <p>Little Red Riding Hood (<a href="#s3.1">Story 3.1</a>) </p>
      <p>Jack goes up the hill (<a href="#s3.1">Story 3.1<i>a</i>
      </a>) to fetch a pail of water.</p>
</t>

说明

我们检查,看看是否匹配的字符串是当前文本节点的后缀 - 如果是,那么我们也复制后的第一个同级元素。

更新

在注释的OP树立了新的,额外的需求-也改变<i><em>

这要求只有轻微的更新上面的解决方案:

<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="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="p/text()[matches(., 'Story [0-9]+(\.[0-9]+)')]">
    <xsl:variable name="vCur" select="."/>
    <xsl:variable name="pContent" select="string(.)"/>
    <xsl:analyze-string select="$pContent" regex="Story [0-9]*\.[0-9]*" flags="i">
      <xsl:matching-substring>
        <xsl:variable name="figureToTargetId">
          <xsl:analyze-string select="." regex="[0-9]*\.[0-9]*">
            <xsl:matching-substring>
              <xsl:value-of select="concat('s',.)"/>
            </xsl:matching-substring>
          </xsl:analyze-string>
        </xsl:variable>
        <a href="#{$figureToTargetId}">
         <xsl:value-of select="."/>
         <xsl:if test="not(matches($vCur, 'Story [0-9]+(\.[0-9]+).+$'))">
          <xsl:apply-templates mode="match" select="$vCur/following-sibling::*[1]"/>
         </xsl:if>
        </a>
      </xsl:matching-substring>
      <xsl:non-matching-substring><xsl:value-of select="."/></xsl:non-matching-substring>
    </xsl:analyze-string>
 </xsl:template>
 <xsl:template match=
  "p/*[preceding-sibling::node()[1]
         [self::text()
        and
          matches(., 'Story [0-9]+(\.[0-9]+)$')]
         ]"/>
 <xsl:template mode="match" match=
  "p/i[preceding-sibling::node()[1]
         [self::text()
        and
          matches(., 'Story [0-9]+(\.[0-9]+)$')]
         ]">
  <em><xsl:apply-templates/></em>
 </xsl:template>

</xsl:stylesheet>


文章来源: Finding mixed XML content with regular expressions