我是XSLT的新手,我正在研究一个小例子,我希望使用XSLT转换XML输入文件以生成文本文件。
这是我输入的xml文件:
<?xml version="1.0" ?>
<result>
<users>
<user>
<user-name>user 1</user-name>
<blood-group>A-</blood-group>
<id>4</id>
<col1>c1</col1>
<col2>c2</col2>
<col4>c4</col4>
</user>
<user>
<user-name>user 2</user-name>
<blood-group>B+</blood-group>
<id>3</id>
<col3>c3</col3>
<col4>c4</col4>
</user>
</users>
</result>
我希望在使用XSLT转换后得到这样的输出:
User Name | Blood Group | Id | col1 | col2 | col3 | col4
user 1 | A- | 4 | c1 | null | null | null
user 1 | A- | 4 | null | c2 | null | null
user 1 | A- | 4 | null | null | null | c4
user 2 | B+ | 3 | null | null | c3 | null
user 2 | B+ | 3 | null | null | null | c4
这个想法是每个记录将以记录所具有的col
元素的数量重复,并且输出文本的每一行将具有特定单个col
元素的值以及所有其他元素col
的值为null
。
我已经创建了一个这样的XSL文件:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="str">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/result">
<xsl:text>User Name | Blood Group | Id | col1 | col2 | col3 | col4 </xsl:text>
<xsl:for-each select="users/user">
<xsl:value-of select="str:align(user-name, ' | ', 'left')" />
<xsl:value-of select="str:align(blood-group, ' | ', 'left')" />
<xsl:value-of select="str:align(id, ' | ', 'left')" />
<xsl:value-of select="str:align(col1, ' | ', 'left')" />
<xsl:value-of select="str:align(col2, ' | ', 'left')" />
<xsl:value-of select="str:align(col3, ' | ', 'left')" />
<xsl:value-of select="col4" />
<xsl:if test="position()!=last()">
<xsl:text> </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
通过这个XSL,我得到了输出:
User Name | Blood Group | Id | col1 | col2 | col3 | col4
user 1 | A- | 4 | c1 | c2 | | c4
user 2 | B+ | 3 | | | c3 | c4
我不清楚可以使用哪些函数来获得所需的输出。有人可以帮助我吗?
帮助我进行转换的java代码是:
public static void main(String[] args) {
String path="/";
String xml = path+"input.xml";
String xslt = path+"input.xsl";
String output = path+"output.txt";
try {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer tr = tf.newTransformer(new StreamSource(xslt));
tr.transform(new StreamSource(xml), new StreamResult(
new FileOutputStream(output)));
System.out.println("Output to " + output);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace();
}
}
更新
使用迈克尔答案中提供的XSL文件,输出为:
User Name | Blood Group | Id | col1 | col2 | col3 | col4
user 1 | A- | 4 | c1 | | |
user 2 | B+ | 3 | | | | c4
user 2 | B+ | 3 | | | c3 |
user 2 | B+ | 3 | | | | c4
答案 0 :(得分:2)
以这种方式试试吗?
XSLT 1.0 (需要支持EXSLT str:align()函数)
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="str">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/result">
<xsl:text>User Name | Blood Group | Id | col1 | col2 | col3 | col4 </xsl:text>
<xsl:for-each select="users/user/*[starts-with(name(), 'col')]">
<xsl:value-of select="str:align(../user-name, ' | ', 'left')" />
<xsl:value-of select="str:align(../blood-group, ' | ', 'left')" />
<xsl:value-of select="str:align(../id, ' | ', 'left')" />
<xsl:value-of select="str:align(self::col1, ' | ', 'left')" />
<xsl:value-of select="str:align(self::col2, ' | ', 'left')" />
<xsl:value-of select="str:align(self::col3, ' | ', 'left')" />
<xsl:value-of select="self::col4" />
<xsl:if test="position()!=last()">
<xsl:text> </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:1)
你需要一个嵌套的for-each over col元素:
<xsl:template match="/result">
<xsl:text>User Name | Blood Group | Id | col1 | col2 | col3 | col4 </xsl:text>
<xsl:for-each select="users/user">
<xsl:for-each select="*[starts-with(local-name(), 'col')]">
<xsl:value-of select="str:align(../user-name, ' | ', 'left')" />
<xsl:value-of select="str:align(../blood-group, ' | ', 'left')" />
<xsl:value-of select="str:align(../id, ' | ', 'left')" />
<xsl:value-of select="str:align(self::col1, ' | ', 'left')" />
<xsl:value-of select="str:align(self::col2, ' | ', 'left')" />
<xsl:value-of select="str:align(self::col3, ' | ', 'left')" />
<xsl:value-of select="self::col4" />
<xsl:if test="position()!=last()">
<xsl:text> </xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:if test="position()!=last()">
<xsl:text> </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
只有空结果而不是null。如果您可以使用XSLT 2.0,则可以使用自定义功能。
答案 2 :(得分:1)
这是一个部分答案,显示如何为缺少的列获取null
而不是空字符串
现在你有两个单独的答案,展示了如何用你需要的形状建立一个表格,拼图的最后一部分是如何把单词&#34; null&#34;在当前空白列中。为此,你可以使用这样的技巧:而不是简单地使用self::colN
中的value-of
,使用
substring(concat('null', self::colN), 5*boolean(self::colN))
这是有效的,因为boolean(self::colN)
如果当前节点是colN
则为真,否则为假,当被视为数字时,true为1且false为0.因此,在真实情况下,这变为
substring('nullc1', 5) => 'c1'
并且在错误的情况下它变成
substring('null', 0) => 'null'
答案 3 :(得分:1)
鉴于这些错误,也许你应该考虑放弃EXSLT功能,转而采用更多的行人&#34;,而是纯粹的XSLT 1.0方法:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:variable name="spaces" select="' '" />
<xsl:template match="/result">
<xsl:text>User Name | Blood Group | Id | col1 | col2 | col3 | col4 </xsl:text>
<xsl:for-each select="users/user/*[starts-with(name(), 'col')]">
<xsl:value-of select="concat(substring(concat(../user-name, $spaces), 1, 10), '| ')" />
<xsl:value-of select="concat(substring(concat(../blood-group, $spaces), 1, 12), '| ')" />
<xsl:value-of select="concat(substring(concat(../id, $spaces), 1, 3), '| ')" />
<xsl:value-of select="concat(substring(concat(self::col1, $spaces), 1, 5), '| ')" />
<xsl:value-of select="concat(substring(concat(self::col2, $spaces), 1, 5), '| ')" />
<xsl:value-of select="concat(substring(concat(self::col3, $spaces), 1, 5), '| ')" />
<xsl:value-of select="self::col4" />
<xsl:if test="position()!=last()">
<xsl:text> </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>