将分层文本列表转换为离散列表

时间:2016-03-03 19:11:27

标签: xslt awk hierarchical-data

从大型层次结构中提取一个深度级别的智能方法是什么?想象一下以下制表符分隔的分层文本列表:

plants
   fruits
      apples
      bananas
      cherries
   trees
      oaks
      maples
   vegetables
      onions
      peppers

目标是仅输出具有一个深度级别的子列表:

plants
   fruits
   trees
   vegetables

fruits
   apples
   bananas
   cherries

trees
   oaks
   maples

vegetables
   onions
   peppers

应该在Mac上以及更大/更深的文件上工作。例如,这是一个更大的文件:

life
    animals
        mammals
            dogs
            cats
            rabbits
        fish
            salmon
        birds
    plants
        fruits
            apples
            bananas
            cherries
            mangoes
        trees
            oaks
            maples
            birch
            pine
        vegetables
            onions
            peppers

这将是较大输入的输出:

life
    animals
    plants

animals
    mammals
    fish
    birds

mammals
    dogs
    cats
    rabbits

fish
    salmon

plants
    fruits
    trees
    vegetables

fruits
    apples
    bananas
    cherries
    mangoes

trees
    oaks
    maples
    birch
    pine

vegetables
    onions
    peppers

1 个答案:

答案 0 :(得分:1)

正如您已将问题标记为XSLT,我发布了一个XSLT 3.0解决方案,该解决方案应该与商业版本的Saxon 9.6(例如oXygen提供)或Saxon 9.7或Exselt一起使用:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="xs math mf"
    version="3.0">

<xsl:param name="text-uri" as="xs:string" select="'test2016030301.txt'"/>

<xsl:param name="indent" as="xs:string" select="'&#9;'"/>

<xsl:output method="text"/>

<xsl:function name="mf:group" as="element(item)*">
    <xsl:param name="lines" as="xs:string*"/>
    <xsl:param name="level" as="xs:integer"/>
    <xsl:for-each-group select="$lines" group-starting-with=".[. instance of xs:string and matches(., '^' || string-join((1 to $level)!$indent) || '\w')]">
        <item data="{normalize-space()}">
            <xsl:sequence select="mf:group(current-group()[position() gt 1], $level + 1)"/>
        </item>
    </xsl:for-each-group>
</xsl:function>

<xsl:template name="main" match="/">
    <xsl:apply-templates select="mf:group(unparsed-text-lines($text-uri), 0)"/>
</xsl:template>

<xsl:template match="item">
    <xsl:value-of select="@data, */($indent || @data)" separator="&#10;"/>
    <xsl:text>&#10;&#10;</xsl:text>
    <xsl:apply-templates select="item[item]"/>
</xsl:template>
</xsl:stylesheet>

使用it:main调用XSLT,并将文本文件的URI作为参数text-uri