XSLT中的嵌套循环用于动态构建XML

Fun*_*arn 1 xslt loops nested dynamic

我是StackOverflow的新用户,因此,如果我无意违反了任何论坛规则,请原谅我。

我正在从Cognos获取XML文档输出,我希望将其用作Crystal报表的输入。但是,Crystal Report所需的XML格式与Cognos输出的XML格式不同。

我正在尝试使用XSLT转换输入XML文档(Cognos),以获取Crystal所需的XML。

设置了上下文之后,下面是来自Cognos的Input XML:

<?xml version="1.0"?>
<dataset>
<metadata>
    <item Name="EmpId" />
    <item Name="EmpName" />
    <item Name="DeptName" />
</metadata>
<data>
    <rows>
        <row>
            <value>1</value>
            <value>John</value>
            <value>Finance</value>
        </row>
        <row>
            <value>2</value>
            <value>Peter</value>
            <value>Admin</value>
        </row>
    </rows>
</data>
Run Code Online (Sandbox Code Playgroud)

Crystal Report所需的XML格式:

<?xml version="1.0"?>
<dataset>
<row>
    <EmpId>1</EmpId>
    <EmpName>John</EmpName>
    <DeptName>Finance</DeptName>
</row>
<row>
    <EmpId>2</EmpId>
    <EmpName>Peter</EmpName>
    <DeptName>Admin</DeptName>
</row>
</dataset>
Run Code Online (Sandbox Code Playgroud)

我在XSLT下方编写了所需的转换:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<dataset>
<xsl:for-each select="./dataset/data/rows/row">
    <row>
        <xsl:for-each select="/dataset/metadata/item">
            <xsl:element name="{@Name}">
                <xsl:for-each select="/dataset/data/rows/row/value">
                    <xsl:value-of select="."/>
                </xsl:for-each>                 
            </xsl:element>
        </xsl:for-each>             
    </row>
</xsl:for-each>
</dataset>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

我得到以下输出:

<?xml version="1.0" encoding="UTF-16"?>
<dataset>
<row>
    <EmpId>1JohnFinance2PeterAdmin</EmpId>
    <EmpName>1JohnFinance2PeterAdmin</EmpName>
    <DeptName>1JohnFinance2PeterAdmin</DeptName>
</row>
<row>
    <EmpId>1JohnFinance2PeterAdmin</EmpId>
    <EmpName>1JohnFinance2PeterAdmin</EmpName>
    <DeptName>1JohnFinance2PeterAdmin</DeptName>
</row>
Run Code Online (Sandbox Code Playgroud)

请告诉我,我要去哪里了。

任何帮助将不胜感激。

提前致谢。

问候

Dim*_*hev 5

这个简短的转换

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:variable name="vNames" select="/*/metadata/*/@Name"/> 

 <xsl:template match="/*/data">
     <dataset><xsl:apply-templates/></dataset>
 </xsl:template>

 <xsl:template match="row">
  <row><xsl:apply-templates/></row>
 </xsl:template>

 <xsl:template match="row/*">
  <xsl:variable name="vPos" select="position()"/>
  <xsl:element name="{$vNames[$vPos]}"><xsl:apply-templates/></xsl:element>
 </xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

当应用于提供的XML文档时(添加了缺少的结束标记以使其格式正确):

<dataset>
    <metadata>
        <item Name="EmpId" />
        <item Name="EmpName" />
        <item Name="DeptName" />
    </metadata>
    <data>
        <rows>
            <row>
                <value>1</value>
                <value>John</value>
                <value>Finance</value>
            </row>
            <row>
                <value>2</value>
                <value>Peter</value>
                <value>Admin</value>
            </row>
        </rows>
    </data>
</dataset>
Run Code Online (Sandbox Code Playgroud)

产生想要的正确结果:

<dataset>
   <row>
      <EmpId>1</EmpId>
      <EmpName>John</EmpName>
      <DeptName>Finance</DeptName>
   </row>
   <row>
      <EmpId>2</EmpId>
      <EmpName>Peter</EmpName>
      <DeptName>Admin</DeptName>
   </row>
</dataset>
Run Code Online (Sandbox Code Playgroud)

说明

  1. 使用模板和XSLT模板选择机制来完成这项工作。作为XSLT通常我们宁愿xsl:apply-templatesxsl:for-each-从而获得更简单,更具扩展性,更易于理解和维护的代码。这是几乎100%的“推送样式”解决方案的示例。

  2. 使用xsl:variable得到(一劳永逸)的节点,我们将与不断努力。

  3. 保存position()变量以供以后在其他上下文中使用- position()取决于上下文。