我想用xslt重新排列xml。
源xml如下:
<?xml version="1.0" encoding="UTF-8" ?>
<studentDetails>
<departments>
<name>IT</name>
<name>CSE</name>
<name>EEE</name>
</departments>
<students> // Want to arrange students and marks alternatively
<student>
<name>aaa</name>
<age>20</age>
</student>
<student>
<name>bbb</name>
<age>25</age>
</student>
<student>
<name>ccc</name>
<age>27</age>
</student>
<student>
<name>ddd</name>
<age>23</age>
</student>
<marks>
<maths>60</maths>
<english>65</english>
</marks>
<marks>
<maths>70</maths>
<english>75</english>
</marks>
<marks>
<maths>80</maths>
<english>85</english>
</marks>
<marks>
<maths>90</maths>
<english>95</english>
</marks>
</students>
</studentDetails>
我想以这种方式输出:
<?xml version="1.0" encoding="UTF-8" ?>
<studentDetails>
<departments>
<name>IT</name>
<name>CSE</name>
<name>EEE</name>
</departments>
<students>
<student>
<name>aaa</name>
<age>20</age>
</student>
<marks>
<maths>60</maths>
<english>65</english>
</marks>
<student>
<name>bbb</name>
<age>25</age>
</student>
<marks>
<maths>70</maths>
<english>75</english>
</marks>
<student>
<name>ccc</name>
<age>27</age>
</student>
<marks>
<maths>80</maths>
<english>85</english>
</marks>
<student>
<name>ddd</name>
<age>23</age>
</student>
<marks>
<maths>90</maths>
<english>95</english>
</marks>
</students>
</studentDetails>
1)。 <student>
代码的数量等于<marks>
的代号
2)。 <student>
和<marks>
的序列是线性的,<student>
的第一次出现后应首先出现<marks>
我尝试了以下xslt:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="countVar" select="count(studentDetails/students/student)"></xsl:variable>
<xsl:variable name="i" select="0"></xsl:variable>
<xsl:template match="/">
<xsl:for-each select="1 to $countVar">
<xsl:variable name="counter" select="$i + 1"></xsl:variable>
<xsl:choose>
<xsl:when test="(position() mod 2) = 0">
<xsl:copy-of select="studentDetails/students/marks[$counter]"></xsl:copy-of>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="studentDetails/students/student[$counter]"></xsl:copy-of>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
我收到以下错误:
第11行出错 XPTY0020:子轴的上下文项的必需项类型是node();供应 值具有项类型xs:integer
此处的在线版本:http://xsltransform.net/gWmuiJw
请告诉我哪里出错了。提前致谢。! :)
答案 0 :(得分:2)
当你这样做时:
<xsl:for-each select="1 to $countVar">
您正在将上下文从XML输入切换到生成的整数序列。在这种情况下,您尝试使用的XPath "studentDetails/students/marks"
毫无意义。
为什么不尝试更简单的事情:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="student">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
<xsl:variable name="i" select="position()" />
<xsl:copy-of select="../marks[$i]"/>
</xsl:template>
<xsl:template match="marks"/>
</xsl:stylesheet>
注意强>:
恕我直言,一种在单个元素下包装学生的所有细节的格式,例如:
<students>
<student>
<name>aaa</name>
<age>20</age>
<marks>
<maths>60</maths>
<english>65</english>
</marks>
</student>
...
<students>
会更有用。
身份转换模板应用于<students>
元素时,会将模板应用于<students>
的所有子节点 - 不仅仅是{ {1}}个节点。
在您的示例中,<student>
元素在其子元素中也有一个注释节点(实际上,它是一个文本节点,但对于此解释的目的没有任何区别)。每个子节点的位置在<students>
指令选择的节点集的上下文中计算(这称为current node list)。因此,示例中第一个xsl:apply templates
节点的位置实际上是#2 - 因为注释节点占用位置#1。
这在实际制作中不应该是一个问题,如果在您的真实XML输入中,除了<student>
之外,<students>
不会是任何子节点。如果您无法确定,请在样式表中再添加一个模板:
<student>
从当前节点列表中排除<xsl:template match="students">
<xsl:copy>
<xsl:apply-templates select="student"/>
</xsl:copy>
</xsl:template>
以外的任何节点。