<root>
<food>
<id>fruits</id>
<parent />
<level>1</level>
</food>
<food>
<id>sourFruits</id>
<parent>fruits</parent>
<level>2</level>
</food>
<food>
<id>sweetFruits</id>
<parent>fruits</parent>
<level>2</level>
</food>
<food>
<id>lemon</id>
<parent>sourFruits</parent>
<level>3</level>
</food>
<food>
<id>grapes</id>
<parent>sweetFruits</parent>
<level>3</level>
</food>
<food>
<id>oranges</id>
<parent>sweetFruits</parent>
<level>3</level>
</food>
</root>
level标记表示层次结构(要形成的逻辑树的节点级别)。 我需要将这个xml(上面)转换为另一个xml,如下所示。 图片如下: - 水果是根本要素。 水果有两个孩子sourFruits和sweetFruits。 sourFruits有一个孩子柠檬和sweetFruits有橙子和葡萄作为孩子。
此时我真的很困惑......
<goodFoods>
<foodType>
<name>fruits</name>
<taste>
<tasteType>sourFruits</tasteType>
<fruit>
<fruitname>lemon</fruitname>
</fruit>
</taste>
<taste>
<tasteType>sweetFruits</tasteType>
<fruit>
<fruitname>grapes</fruitname>
</fruit>
<fruit>
<fruitname>oranges</fruitname>
</fruit>
</taste>
</foodType>
</goodFoods>
答案 0 :(得分:0)
您希望通过foot
及其父级引用level
元素,使用XSLT,您可以使用密钥,在XSLT 3.0中使用复合键
<xsl:key name="children" match="food" composite="yes" use="xs:integer(level), string(parent)"/>
很好,对于早期版本的XSLT,您需要使用单个键值,例如将级别和父级连接起来的字符串,例如。
<xsl:key name="children" match="food" use="concat(level, '|', parent)"/>
然后,只需要将每个级别转换为目标格式,并使用XSLT 3.0找到具有密钥的子项
<xsl:template match="root">
<goodFoods>
<xsl:apply-templates select="key('children', (1, ''))"/>
</goodFoods>
</xsl:template>
<xsl:template match="food[level = 1]">
<foodType>
<name>{id}</name>
<xsl:apply-templates select="key('children', (level + 1, string(id)))"/>
</foodType>
</xsl:template>
<xsl:template match="food[level = 2]">
<taste>
<tasteType>{id}</tasteType>
<xsl:apply-templates select="key('children', (level + 1, string(id)))"/>
</taste>
</xsl:template>
<xsl:template match="food[level = 3]">
<fruit>
<fruitName>{id}</fruitName>
</fruit>
</xsl:template>
使用XSLT 3的完整样式表是
<?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"
exclude-result-prefixes="xs math"
expand-text="yes"
version="3.0">
<xsl:key name="children" match="food" composite="yes" use="xs:integer(level), string(parent)"/>
<xsl:output indent="yes"/>
<xsl:template match="root">
<goodFoods>
<xsl:apply-templates select="key('children', (1, ''))"/>
</goodFoods>
</xsl:template>
<xsl:template match="food[level = 1]">
<foodType>
<name>{id}</name>
<xsl:apply-templates select="key('children', (level + 1, string(id)))"/>
</foodType>
</xsl:template>
<xsl:template match="food[level = 2]">
<taste>
<tasteType>{id}</tasteType>
<xsl:apply-templates select="key('children', (level + 1, string(id)))"/>
</taste>
</xsl:template>
<xsl:template match="food[level = 3]">
<fruit>
<fruitName>{id}</fruitName>
</fruit>
</xsl:template>
</xsl:stylesheet>
使用XSLT 1或2键,您需要稍微调整模板,例如
<xsl:template match="food[level = 1]">
<foodType>
<name>
<xsl:value-of select="id"/>
</name>
<xsl:apply-templates select="key('children', concat(level + 1, '|', id))"/>
</foodType>
</xsl:template>
应该清楚如何调整其他模板。
答案 1 :(得分:0)
不确定XSLT,但是这里是如何在xsh中完成的:
open file.xml ;
for &{ sort :n :d :k level /root/food[parent!=""] } {
my $f = . ;
mv $f into ../food[id=$f/parent] ;
}
rename goodFoods /root ;
rename fruit //food[level = 3] ;
rename taste //food[level = 2] ;
rename foodType //food[level = 1] ;
rename fruitname //fruit/id ;
rename tasteType //taste/id ;
rename name //foodType/id ;
remove ( //level | //parent ) ;
save :b ;
使用xmllint --format
处理后,输出为
<goodFoods>
<foodType>
<name>fruits</name>
<taste>
<tasteType>sourFruits</tasteType>
<fruit>
<fruitname>lemon</fruitname>
</fruit>
</taste>
<taste>
<tasteType>sweetFruits</tasteType>
<fruit>
<fruitname>grapes</fruitname>
</fruit>
<fruit>
<fruitname>oranges</fruitname>
</fruit>
</taste>
</foodType>
</goodFoods>