我在计算器上一个新的用户,所以请原谅我,如果我的任何论坛规则得到无意中侵犯。
我正在从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>
请让我知道,我要去的地方错了。
任何帮助将高度赞赏。
提前致谢。
问候
这种短期和简单的变换 :
<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>
说明 :
使用模板和XSLT的模板选择机制来完成这项工作。 作为XSLT通常我们宁愿xsl:apply-templates
来xsl:for-each
-从而获得更简单,更具扩展性,更易于理解和维护的代码。 这是一个几乎100%的“推式”解决方案的例子。
使用xsl:variable
获得(一劳永逸),我们将与不断努力的节点。
保存position()
中的变量为在其他上下文中以后使用- position()
是上下文相关的。
我会使用<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>
该dataset
和row
元素我通过匹配和应用一定的模板来创建。 让我们知道这对你的作品。
最好的问候,彼得
感谢您的支持。 定制所提供的解决方案后@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>
希望这可以帮助。