在XSLT的嵌套循环的动态构建XML(Nested loops in XSLT for dynami

2019-10-17 05:23发布

我在计算器上一个新的用户,所以请原谅我,如果我的任何论坛规则得到无意中侵犯。

我正在从COGNOS输出,我想使用的输入Crystal Reports的XML文档。 然而,水晶报表所需的XML格式是COGNOS输出的XML格式不同。

我想变换使用XSLT,从而获得所需XML水晶输入XML文档(COGNOS)。

将其具有上下文,下面是输入XML从COGNOS来:

<?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>

通过水晶报表要求所需的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>

请让我知道,我要去的地方错了。

任何帮助将高度赞赏。

提前致谢。

问候

Answer 1:

这种短期和简单的变换

<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>

当所提供的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>

产生想要的,正确的结果:

<dataset>
   <row>
      <EmpId>1</EmpId>
      <EmpName>John</EmpName>
      <DeptName>Finance</DeptName>
   </row>
   <row>
      <EmpId>2</EmpId>
      <EmpName>Peter</EmpName>
      <DeptName>Admin</DeptName>
   </row>
</dataset>

说明

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

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

  3. 保存position()中的变量为在其他上下文中以后使用- position()是上下文相关的。



Answer 2:

我会使用<template><apply-templates>机制来解决这个问题。 For-each不走这里,我认为正确的方式。

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>

datasetrow元素我通过匹配和应用一定的模板来创建。 让我们知道这对你的作品。

最好的问候,彼得



Answer 3:

感谢您的支持。 定制所提供的解决方案后@DimitreNovatchev我能得到XML的期望转化。 在这里张贴的解决方案,以便它可以帮助别人。

输入XML

<?xml version="1.0"?>
<dataset  xmlns="http://developer.cognos.com/schemas/xmldata/1/"  xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
<metadata>
    <item name="Employee Id" />
    <item name="Employee Name" />
    <item name="Department Name" />
</metadata>
<data>      
    <row>
        <value>1</value>
        <value Salutation="Dr." >John</value>
        <value>Finance</value>
    </row>
    <row>
        <value>2</value>
        <value Salutation="Mr." >Peter</value>
        <value>Admin</value>
    </row>      
</data>

XSLT转换

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:c="http://developer.cognos.com/schemas/xmldata/1/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vNames" select="/*/c:metadata/*/@name" />
<xsl:template match="/*/c:data">
<dataset>
    <xsl:apply-templates/>
</dataset>
</xsl:template>
<xsl:template match="c:row">
<row>
    <xsl:apply-templates/>
</row>
</xsl:template>
<xsl:template match="c:row/*">
<xsl:variable name="vPos" select="position()"/>
<xsl:element name="{translate($vNames[$vPos], ' ', '_')}">
    <xsl:apply-templates select="@*"/>
    <xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="@*">
<xsl:attribute name="{name()}">
    <xsl:value-of select="." />
</xsl:attribute>
</xsl:template>

输出XML

<?xml version="1.0" encoding="UTF-16"?>
<dataset xmlns:c="http://developer.cognos.com/schemas/xmldata/1/">
<row>
    <Employee_Id>1</Employee_Id>
    <Employee_Name Salutation="Dr.">John</Employee_Name>
    <Department_Name>Finance</Department_Name>
</row>
<row>
    <Employee_Id>2</Employee_Id>
    <Employee_Name Salutation="Mr.">Peter</Employee_Name>
    <Department_Name>Admin</Department_Name>
</row>

希望这可以帮助。



文章来源: Nested loops in XSLT for dynamically building XML