使用XSLT从嵌套的XML结构生成元素文本位置的平面列表

时间:2017-06-29 17:38:41

标签: xml xslt xpath

我正在寻找一个示例XML,例如

<alpha>
  <beta>
    Here is <x>some text <y>and more</y> text</x> with <x>a little more text</x>!
  </beta>
</alpha>

我尝试使用XSL将其转换为类似

的内容
x:8,31
x:37,55
y:18,26

确切的格式不是很重要,我试图找出的主要任务是抓住各种<x><y>元素的文本中的位置(可以多次表示并嵌套,如示例中所示,我有两个<x>元素,并且<y>元素中有一个<x>元素。因此,上面所需的输出是x元素从文本位置8开始,到<beta>元素内的文本位置31结束。还有另一个x元素从37到55,y元素从18到26.输出列表的顺序并不重要。

我已经看过substring-beforecount的提及但我无法弄清楚这些工作如何嵌套在未知数量的嵌套中,或者是否可能存在多个嵌套相同的元素出现在文本的各个部分。

只有XSLT可以这样吗?

2 个答案:

答案 0 :(得分:3)

这是一个XSLT 1.0选项,非常类似于Martin的......

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="text()"/>

  <xsl:template match="x|y">
    <xsl:variable name="ancestor" 
      select="generate-id(ancestor::*[not(self::x) and not(self::y)][1])"/>
    <xsl:variable name="preceding">
      <xsl:for-each select="preceding::text()[ancestor::*[generate-id()=$ancestor]]">
        <xsl:value-of select="."/>
      </xsl:for-each>
    </xsl:variable>    
    <xsl:value-of select="concat(name(),':',string-length($preceding),',',
      string-length($preceding) + string-length(),'&#xA;')"/>
    <xsl:apply-templates/>
  </xsl:template>

</xsl:stylesheet>

就像Martin提到的那样,beta中的空格很重要,因为它包含混合内容(文本和元素子)。

如果删除前导/尾随空格......

<alpha>
    <beta>Here is <x>some text <y>and more</y> text</x> with <x>a little more text</x>!</beta>
</alpha>

输出是按要求的......

x:8,31
y:18,26
x:37,55

答案 1 :(得分:2)

使用

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">

    <xsl:output method="text"/>

    <xsl:template match="node()">
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="beta//*">
        <xsl:variable name="preceding-length" select="sum((preceding::text() intersect ancestor::beta//text())/string-length())"/>
        <xsl:value-of select="local-name(), ': ', $preceding-length, ', ', $preceding-length + string-length()"/>
        <xsl:text>&#10;</xsl:text>
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="text()"/>

</xsl:stylesheet>

和你的样本给我的XSLT 2.0处理器

x :  11 ,  34
y :  21 ,  29
x :  40 ,  58

您想要的结果偏移3可能是空格。