我有这种格式的源XML。源的相关部分位于值标记下,嵌套约四个级别,并表示一个或多个数据表,其中元素的格式为:name = TableName-Row# .FieldName 和value = fieldValue 。
<root>
<someData>1</someData>
<otherData>free</otherData>
<parent1>
<parent2>
<parent3>
<values>
<data>
<name>ComputerInfo-1.CPU</name>
<value>4</value>
</data>
<data>
<name>ComputerInfo-1.Memory</name>
<value>32</value>
</data>
<data>
<name>ComputerInfo-1.Storage</name>
<value>1024</value>
</data>
<data>
<name>ComputerInfo-2.CPU</name>
<value>2</value>
</data>
<data>
<name>ComputerInfo-2.Memory</name>
<value>64</value>
</data>
<data>
<name>ComputerInfo-2.Storage</name>
<value>2048</value>
</data>
<data>
<name>ComputerInfo-3.CPU</name>
<value>4</value>
</data>
<data>
<name>ComputerInfo-3.Memory</name>
<value>16</value>
</data>
<data>
<name>ComputerInfo-3.Storage</name>
<value>512</value>
</data>
<data>
<name>UserInfo-1.firstName</name>
<value>Mary</value>
</data>
<data>
<name>UserInfo-1.lastName</name>
<value>Jones</value>
</data>
<data>
<name>UserInfo-1.login</name>
<value>mjones</value>
</data>
<data>
<name>UserInfo-2.firstName</name>
<value>Doctor</value>
</data>
<data>
<name>UserInfo-2.lastName</name>
<value>Who</value>
</data>
<data>
<name>UserInfo-2.login</name>
<value>dwho</value>
</data>
<data>
<name>UserInfo-3.firstName</name>
<value>John</value>
</data>
<data>
<name>UserInfo-3.lastName</name>
<value>Mellencamp</value>
</data>
<data>
<name>UserInfo-3.login</name>
<value>cougar69</value>
</data>
</values>
</parent3>
</parent2>
</parent1>
</root>
所需的结果是一个CSV文件,标题行位于顶部,后跟相应的行:
CPU,Memory,Storage
4,32,1024
2,64,2048
4,16,512
我还想使用变量来保存我想要处理的特定表格,例如
<xsl:variable name="table" select="/root/tableName"/>
这是因为我有能力通过应用程序在我选择的时候在源XML中包含tableName。但是, xsl:key 不允许我在匹配中使用变量,而且我也被迫使用XSLT 1.0。
我的问题是我可以分步进行,但我真的需要在一次变换中这样做 这是我到目前为止所拥有的。
我可以将Source XML传递给这个转换:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/root/parent1/parent2/parent3/values/data">
<xsl:element name="{name}">
<xsl:value-of select="value" />
</xsl:element>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<values>
<xsl:apply-templates select="//values/node()"/>
</values>
</xsl:template>
</xsl:stylesheet>
它会产生这个结果:
<values>
<ComputerInfo-1.CPU>4</ComputerInfo-1.CPU>
<ComputerInfo-1.Memory>32</ComputerInfo-1.Memory>
<ComputerInfo-1.Storage>1024</ComputerInfo-1.Storage>
<ComputerInfo-2.CPU>2</ComputerInfo-2.CPU>
<ComputerInfo-2.Memory>64</ComputerInfo-2.Memory>
<ComputerInfo-2.Storage>2048</ComputerInfo-2.Storage>
<ComputerInfo-3.CPU>4</ComputerInfo-3.CPU>
<ComputerInfo-3.Memory>16</ComputerInfo-3.Memory>
<ComputerInfo-3.Storage>512</ComputerInfo-3.Storage>
<UserInfo-1.firstName>Mary</UserInfo-1.firstName>
<UserInfo-1.lastName>Jones</UserInfo-1.lastName>
<UserInfo-1.login>mjones</UserInfo-1.login>
<UserInfo-2.firstName>Doctor</UserInfo-2.firstName>
<UserInfo-2.lastName>Who</UserInfo-2.lastName>
<UserInfo-2.login>dwho</UserInfo-2.login>
<UserInfo-3.firstName>John</UserInfo-3.firstName>
<UserInfo-3.lastName>Mellencamp</UserInfo-3.lastName>
<UserInfo-3.login>cougar69</UserInfo-3.login>
</values>
然后我可以获取此结果并应用以下转换:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:key name="elementByRow" match="/*/*[contains(name(), 'ComputerInfo')]" use="substring-before(name(), '.')"/>
<xsl:template match="/*">
<values>
<xsl:apply-templates select="*[generate-id() = generate-id(key('elementByRow', substring-before(name(), '.'))[1])]" />
</values>
</xsl:template>
<xsl:template match="*">
<Row>
<xsl:for-each select="key('elementByRow', substring-before(name(), '.'))">
<xsl:element name="{substring-after(name(), '.')}">
<xsl:value-of select="." />
</xsl:element>
</xsl:for-each>
</Row>
</xsl:template>
</xsl:stylesheet>
将产生这个结果:
<values>
<Row>
<CPU>4</CPU>
<Memory>32</Memory>
<Storage>1024</Storage>
</Row>
<Row>
<CPU>2</CPU>
<Memory>64</Memory>
<Storage>2048</Storage>
</Row>
<Row>
<CPU>4</CPU>
<Memory>16</Memory>
<Storage>512</Storage>
</Row>
</values>
我专门针对这个以前的格式,因为我在这里发现了另一个帖子(convert xml document to comma delimited (CSV) file using xslt stylesheet),它允许我获取此结果并应用上述帖子中的变换来获得所需的结果。以下是该帖子的转换参考:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="field" match="/*/*/*" use="name()" />
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:for-each select="*/*/*[generate-id() = generate-id(key('field',name())[1])]">
<xsl:value-of select="name()" />
<xsl:if test="position() != last()">,</xsl:if>
</xsl:for-each>
<xsl:text> </xsl:text>
<xsl:apply-templates select="*/*" mode="row"/>
</xsl:template>
<xsl:template match="*" mode="row">
<xsl:variable name="row" select="*" />
<xsl:for-each select="/*/*/*[generate-id() = generate-id(key('field',name())[1])]">
<xsl:variable name="name" select="name()" />
<xsl:apply-templates select="$row[name()=$name]" mode="data" />
<xsl:if test="position() != last()">,</xsl:if>
</xsl:for-each>
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template match="*" mode="data">
<xsl:choose>
<xsl:when test="contains(text(),',')">
<xsl:text>"</xsl:text>
<xsl:call-template name="doublequotes">
<xsl:with-param name="text" select="text()" />
</xsl:call-template>
<xsl:text>"</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="." />
</xsl:otherwise>
</xsl:choose>
<xsl:if test="position() != last()">,</xsl:if>
</xsl:template>
<xsl:template name="doublequotes">
<xsl:param name="text" />
<xsl:choose>
<xsl:when test="contains($text,'"')">
<xsl:value-of select="concat(substring-before($text,'"'),'""')" />
<xsl:call-template name="doublequotes">
<xsl:with-param name="text" select="substring-after($text,'"')" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
答案 0 :(得分:2)
你不能简单地这样做:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8"/>
<xsl:template match="/">
<xsl:text>CPU,Memory,Storage </xsl:text>
<xsl:for-each select="root/parent1/parent2/parent3/values/data[starts-with(./name, 'ComputerInfo')]">
<xsl:value-of select="value" />
<xsl:choose>
<xsl:when test="position() mod 3">
<xsl:value-of select="','" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="' '" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
假设数据的结构是不变的。
<强>增加:强>
现在,如果您想概括上述内容,可以执行以下操作:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="tableName" select="root/tableName"/>
<xsl:variable name="tableData" select="root/parent1/parent2/parent3/values/data[substring-before(./name, '-')=$tableName]" />
<xsl:variable name="firstRow" select="$tableData[substring-before(substring-after(./name, '-'), '.')='1']" />
<xsl:variable name="countCols" select="count($firstRow)" />
<xsl:for-each select="$firstRow">
<xsl:value-of select="substring-after(./name, '-1.')" />
<xsl:choose>
<xsl:when test="position() mod $countCols">
<xsl:value-of select="','" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="' '" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:for-each select="$tableData">
<xsl:value-of select="value" />
<xsl:choose>
<xsl:when test="position() mod $countCols">
<xsl:value-of select="','" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="' '" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
给出输入:
<root>
<tableName>ComputerInfo</tableName>
<someData>1</someData>
<otherData>free</otherData>
<parent1>
<parent2>
<parent3>
<values>
<data>
<name>ComputerInfo-1.CPU</name>
<value>4</value>
</data>
<data>
<name>ComputerInfo-1.Memory</name>
<value>32</value>
</data>
<data>
<name>ComputerInfo-1.Storage</name>
<value>1024</value>
</data>
<data>
<name>ComputerInfo-1.Age</name>
<value>11</value>
</data>
<data>
<name>ComputerInfo-2.CPU</name>
<value>2</value>
</data>
<data>
<name>ComputerInfo-2.Memory</name>
<value>64</value>
</data>
<data>
<name>ComputerInfo-2.Storage</name>
<value>2048</value>
</data>
<data>
<name>ComputerInfo-2.Age</name>
<value>22</value>
</data>
<data>
<name>ComputerInfo-3.CPU</name>
<value>4</value>
</data>
<data>
<name>ComputerInfo-3.Memory</name>
<value>16</value>
</data>
<data>
<name>ComputerInfo-3.Storage</name>
<value>512</value>
</data>
<data>
<name>ComputerInfo-3.Age</name>
<value>33</value>
</data>
<data>
<name>UserInfo-1.firstName</name>
<value>Mary</value>
</data>
<data>
<name>UserInfo-1.lastName</name>
<value>Jones</value>
</data>
<data>
<name>UserInfo-1.login</name>
<value>mjones</value>
</data>
<data>
<name>UserInfo-2.firstName</name>
<value>Doctor</value>
</data>
<data>
<name>UserInfo-2.lastName</name>
<value>Who</value>
</data>
<data>
<name>UserInfo-2.login</name>
<value>dwho</value>
</data>
<data>
<name>UserInfo-3.firstName</name>
<value>John</value>
</data>
<data>
<name>UserInfo-3.lastName</name>
<value>Mellencamp</value>
</data>
<data>
<name>UserInfo-3.login</name>
<value>cougar69</value>
</data>
</values>
</parent3>
</parent2>
</parent1>
</root>
它会返回:
CPU,Memory,Storage,Age
4,32,1024,11
2,64,2048,22
4,16,512,33
但如果您将<tableName>
更改为“UserInfo”,则现在会生成相同的样式表:
firstName,lastName,login
Mary,Jones,mjones
Doctor,Who,dwho
John,Mellencamp,cougar69