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

XSLT中用于动态构建XML的嵌套循环,xslt,loops,dynamic,nested,Xslt,Loops,Dynamic,Nested,我是StackOverflow的新用户,如果我无意中违反了任何论坛规则,请原谅我 我从Cognos获得一个XML文档输出,我想将其用作Crystal reports的输入。 然而,Crystal Report所需的XML格式与Cognos输出的XML格式不同 我试图使用XSLT转换输入XML文档Cognos,以获得Crystal所需的XML 设置好上下文后,下面是来自Cognos的输入XML: <?xml version="1.0"?> <dataset> <met

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

我从Cognos获得一个XML文档输出,我想将其用作Crystal reports的输入。 然而,Crystal Report所需的XML格式与Cognos输出的XML格式不同

我试图使用XSLT转换输入XML文档Cognos,以获得Crystal所需的XML

设置好上下文后,下面是来自Cognos的输入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>
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>
我已经为所需的转换编写了以下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>
我得到以下输出:

<?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>
请告诉我,我错在哪里

任何帮助都将不胜感激

提前谢谢

关于

我将使用和机制来解决此问题。我认为,在这里,每个人都不是正确的选择

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>
</dataset>  
将此样式表应用于它:

<?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:apply-templates select="//row"/>
    </dataset>
</xsl:template>

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

<xsl:template match="value">
    <xsl:variable name="index">
        <xsl:number/>
    </xsl:variable>
    <xsl:element name="{../../../../metadata/item[position() = $index]/@Name}">
        <xsl:apply-templates select="@* | node()"/>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>
您将获得以下输出:

<?xml version="1.0" encoding="utf-8"?>
<dataset>
<row>
    <EmpId>1</EmpId>
    <EmpName>John</EmpName>
    <DeptName>Finance</DeptName>
</row>
<row>
    <EmpId>2</EmpId>
    <EmpName>Peter</EmpName>
    <DeptName>Admin</DeptName>
</row>
</dataset>
我通过匹配和应用某些模板创建的数据集和行元素。 让我们知道这是否对您有效

致以最良好的祝愿, Peter

我会使用和机制来解决这个问题。我认为,在这里,每个人都不是正确的选择

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>
</dataset>  
将此样式表应用于它:

<?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:apply-templates select="//row"/>
    </dataset>
</xsl:template>

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

<xsl:template match="value">
    <xsl:variable name="index">
        <xsl:number/>
    </xsl:variable>
    <xsl:element name="{../../../../metadata/item[position() = $index]/@Name}">
        <xsl:apply-templates select="@* | node()"/>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>
您将获得以下输出:

<?xml version="1.0" encoding="utf-8"?>
<dataset>
<row>
    <EmpId>1</EmpId>
    <EmpName>John</EmpName>
    <DeptName>Finance</DeptName>
</row>
<row>
    <EmpId>2</EmpId>
    <EmpName>Peter</EmpName>
    <DeptName>Admin</DeptName>
</row>
</dataset>
我通过匹配和应用某些模板创建的数据集和行元素。 让我们知道这是否对您有效

致以最良好的祝愿, 彼得

这个简短而简单的转变:

<?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>
应用于提供的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>
生成所需的正确结果:

说明:

使用模板和XSLT模板选择机制来完成这项工作。作为XSLT中的一条规则,我们更喜欢这样做——从而获得更简单、更可扩展、更易于理解和维护的代码。这是一个几乎100%推式解决方案的示例

使用它可以一次性获得我们将经常使用的节点

保存在一个变量中供以后在其他上下文中使用-位置取决于上下文

这个简短而简单的转换:

<?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>
应用于提供的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>
生成所需的正确结果:

说明:

使用模板和XSLT模板选择机制来完成这项工作。作为XSLT中的一条规则,我们更喜欢这样做——从而获得更简单、更可扩展、更易于理解和维护的代码。这是一个几乎100%推式解决方案的示例

使用它可以一次性获得我们将经常使用的节点

保存在一个变量中供以后在其他上下文中使用-位置取决于上下文


谢谢你的支持。在定制@DimitreNovatchev提供的解决方案之后,我能够获得所需的XML转换。在此处发布解决方案,以便它可以帮助其他人

输入XML

XSLT转换

输出XML


希望这能有所帮助。

谢谢您的支持。在定制@DimitreNovatchev提供的解决方案之后,我能够获得所需的XML转换。在此处发布解决方案,以便它可以帮助其他人

输入XML

XSLT转换

输出XML


希望这能有所帮助。

您可以在此处使用xsl:key,使元素名称的查找更整洁、更高效。Peter,与其使用//row作为匹配模式,不如使用//row更简单、更等效。感谢Dimitre的提示,但如果我使用row运行上述xsl,则输出XML为空,它似乎需要/.@Peter,我只是在谈论匹配模式,而不是xsl:apply templates的select属性。使用position可能比使用xsl:number更有效,特别是当xsl:number位于结果树片段中时,这意味着将数字转换为字符串,再转换为变量中保存的树,引用变量时,首先将其转换为字符串,最后再转换为数字。您可以在此处使用xsl:key,以使元素名称的查找更整洁、更高效。Peter,与其使用//行作为匹配模式,只使用:row更简单,也相当于使用:row。谢谢Dimitre的提示,但是如果我使用row运行上面的XSL,输出XML为空,它似乎需要//。@Peter,我只讨论匹配模式,而不是XSL:apply templates的select属性。使用position可能比使用XSL:number更有效,特别是当xsl:number位于结果树片段中时,这意味着您要将一个数字转换为一个字符串,再转换为变量中的一个树,当您引用变量时,您首先要将它转换为一个字符串,最后再转换回一个数字。您好,Dimitre,将名称路径写入变量vName是否会提高性能
彼得,对不起,你什么意思?请重新措辞。@Peter,从节点集中选择第N个节点比计算具有多个反向步骤的复杂XPath表达式更有效-每次我们处理一个值。@Peter:两者都是。可读性和方便性。更短更简单。更灵活—如果由于XML文档的重新构造而需要更改选择必要名称的XPath表达式,那么我只需在变量定义中的一个位置更改XPath表达式。所有剩余的代码都将保持不变。@DimitreNovatchev,感谢您的解决方案和解释。但是,我删除了codeomit xml declaration=yes,以便在输出xml中获取代码。您好,Dimitre,将名称路径写入变量vNames中对性能更好吗?@Peter,对不起,您是什么意思?请重新措辞。@Peter,从节点集中选择第N个节点比计算具有多个反向步骤的复杂XPath表达式更有效-每次我们处理一个值。@Peter:两者都是。可读性和方便性。更短更简单。更灵活—如果由于XML文档的重新构造而需要更改选择必要名称的XPath表达式,那么我只需在变量定义中的一个位置更改XPath表达式。所有剩余的代码都将保持不变。@DimitreNovatchev,感谢您的解决方案和解释。但是,我删除了codeomit xml declaration=yes以在输出xml中获取代码。感谢这帮助我将Cognos Report Studio数据导出为xml。但是需要注意的是:输入XML在末尾缺失,XSLT转换在末尾缺失。在我纠正之前,给我的XML文档结构必须在相同的实体错误中开始和结束。这帮助我将Cognos Report Studio数据导出为XML。但是需要注意的是:输入XML在末尾缺失,XSLT转换在末尾缺失。在我纠正错误之前,提供给我的XML文档结构必须在同一实体中开始和结束