【发布时间】:2015-07-24 00:04:30
【问题描述】:
我有一个由一系列脚本动态生成的 XML 文件。每个部分都可以有名称值对和/或信息表。
我正在尝试创建一个输出每个部分的 XSLT 转换,如果它包含 Format='Table' 则动态生成一个表。
我的示例 XML 如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<QAReport ReportDate="05/03/2015 14:07:33" ReportVersion="3.0" ScriptVersion="1.2015.0428.01" QAStatus="2">
<DiskInformation Display="Disk Information">
<Disks Format="Table">
<Disk>
<DriveLetter>C:</DriveLetter>
<FoundInSBB>True</FoundInSBB>
<StartingOffset>
</StartingOffset>
<BlockSize>4096</BlockSize>
<DriveSize>50</DriveSize>
</Disk>
<Disk>
<DriveLetter>D:</DriveLetter>
<FoundInSBB>True</FoundInSBB>
<StartingOffset>
</StartingOffset>
<BlockSize>4096</BlockSize>
<DriveSize>50</DriveSize>
</Disk>
</Disks>
</DiskInformation>
<DeviceManagerInformation Display="Device Manager Information">
<DeviceManagerErrors Format="Table" />
</DeviceManagerInformation>
<EventLogInformation Display="Event Log Information">
<SystemEventLogErrors Format="Table">
<Event>
<EventID>10009</EventID>
<EventTime>04/27/2015 23:14:20</EventTime>
<EventSource>DCOM</EventSource>
<EventMessage>The description for Event ID -1073731815 in Source DCOM cannot be found. The local computer may not have the necessary registry information or message DLL files to display the message, or you may not have permission to access them. The following information is part of the event: WCDRE56I </EventMessage>
</Event>
<Event>
<EventID>10009</EventID>
<EventTime>04/27/2015 23:14:12</EventTime>
<EventSource>DCOM</EventSource>
<EventMessage>The description for Event ID -1073731815 in Source DCOM cannot be found. The local computer may not have the necessary registry information or message DLL files to display the message, or you may not have permission to access them. The following information is part of the event: WCDRE56I </EventMessage>
</Event>
</SystemEventLogErrors>
</EventLogInformation>
<IISInformation Display="IIS Information">
<IISService Display="IIS Service Status">Running</IISService>
</IISInformation>
<IPInformation Display="IP Information" ReportLevel="20">
<FQDN>Server123.mydomain.com</FQDN>
<DNSDomain Display="DNS Domain">mydomain.com</DNSDomain>
<IPAddress Display="IP Address">10.0.0.101</IPAddress>
<Subnet>255.255.248.0/64</Subnet>
<Gateway>10.0.0.1</Gateway>
<DNSServers Display="DNS Servers" Format="List">
<DNSServer>12.0.0.1</DNSServer>
<DNSServer>12.0.0.2</DNSServer>
</DNSServers>
<DNSSearchSuffixes Display="DNS Search Suffixes" Format="List">
<DNSSearchSuffix>MyDomain.com.com</DNSSearchSuffix>
<DNSSearchSuffix>MyOtherDomain.com</DNSSearchSuffix>
<DNSSearchSuffix>MyThirdDomain.com</DNSSearchSuffix>
</DNSSearchSuffixes>
<DNSRegistrationEnabled>True</DNSRegistrationEnabled>
<NetBIOS>Enabled via DHCP</NetBIOS>
<WindowsFirewallDisabled>True</WindowsFirewallDisabled>
</IPInformation>
<ServerInformation Display="Server Information">
<HostName>Server123</HostName>
<OS>Microsoft Windows Server 2008 R2 Enterprise 64-bit</OS>
<OSVersion Display="OS Version">6.1.7601</OSVersion>
<OSServicePack Display="Service Pack">Service Pack 1</OSServicePack>
<CPUs>1</CPUs>
<Memory>4096</Memory>
</ServerInformation>
</QAReport>
我的 XSLT 看起来像这样
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="2.0" exclude-result-prefixes="xs xdt err fn" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xdt="http://www.w3.org/2005/xpath-datatypes" xmlns:err="http://www.w3.org/2005/xqt-errors">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<table class="NVPair">
<tr>
<th>Report Date</th>
<td>
<xsl:value-of select="/QAReport/@ReportDate"/>
</td>
</tr>
<tr>
<th>QA Status</th>
<td>
<xsl:if test="/QAReport/@QAStatus = 2 ">
<span class="QAPass">
<xsl:value-of select="/QAReport/@QAStatus"/> (OK)</span>
</xsl:if>
<xsl:if test="/QAReport/@QAStatus != 2 ">
<span class="QAFail">
<xsl:value-of select="/QAReport/@QAStatus"/> (Failure)</span>
</xsl:if>
</td>
</tr>
</table>
<xsl:apply-templates select="QAReport/*"/>
</xsl:template>
<xsl:template match="/QAReport/*">
<h3>
<xsl:choose>
<xsl:when test="@Display">
<xsl:value-of select="@Display"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="name(.)"/>
</xsl:otherwise>
</xsl:choose>
</h3>
<xsl:text>
</xsl:text>
<xsl:if test="*/.[not(@Format)]"><!-- format each NVPair first -->
<table class="NVPair">
<xsl:for-each select="*/.[not(@Format='Table')]">
<xsl:call-template name="NVPair"/>
</xsl:for-each>
</table>
</xsl:if>
<xsl:if test="*/.[@Format='Table']"><!-- select each table in the section-->
<xsl:call-template name="QATable"/>
</xsl:if>
</xsl:template>
<xsl:template name="NVPair">
<tr>
<th>
<xsl:value-of select="name(.)"/>
</th>
<td>
<xsl:value-of select="."/>
</td>
</tr>
</xsl:template>
<xsl:template name="QATable">
<h4>
<xsl:value-of select="name(*)"/>
</h4>
<table class="QATable">
<xsl:for-each select="./*/*">
<xsl:value-of select="name(.)"/>
<xsl:choose>
<xsl:when test="position()=1">
<xsl:call-template name="QATableRowFirst"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="QATableRow"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template name="QATableRowFirst">
<thead>
<tr>
<xsl:for-each select="./*">
<td>
<xsl:value-of select="name(.)"/>
</td>
</xsl:for-each>
</tr>
</thead>
<tr>
<xsl:for-each select="./*">
<td>
<xsl:value-of select="."/>
</td>
</xsl:for-each>
</tr>
</xsl:template>
<xsl:template name="QATableRow">
<tr>
<xsl:for-each select="./*">
<td>
<xsl:value-of select="."/>
</td>
</xsl:for-each>
</tr>
</xsl:template>
</xsl:stylesheet>
我有几个问题。
1) 考虑到 NVP 部分是动态的,是否有一种很好的方法可以将第一个 xsl:for-each 循环用作模板。
2) Format='Table' 模板非常难看 - 两个 for-eaches,一个用于行,一个用于列 - 调用模板或应用模板有更好的方法吗?
请记住,在任何时候 XML 都可以有不同的部分,而表虽然在每个部分中是一致的,但可以有任意数量的列。
更新(2015.05-13):
基于@Michael.hor257k,我最终得到了这个,它工作得更好,更简单。
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="2.0" exclude-result-prefixes="xs xdt err fn" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xdt="http://www.w3.org/2005/xpath-datatypes" xmlns:err="http://www.w3.org/2005/xqt-errors">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<link rel="stylesheet" type="text/css" href="Styles/QAReportStyle.css"/>
<table class="NVPair">...</table>
<xsl:apply-templates select="/QACheck/*"/>
</xsl:template>
<xsl:template match="/QACheck/*">
<h3><xsl:value-of select="name(.)"/></h3>
<xsl:choose>
<xsl:when test="*[not(@Format)]">
<!-- format each NVPair first -->
<table class="NVPair">
<xsl:for-each select="*[not(@Format='Table')]">
<xsl:call-template name="NVPair"/>
</xsl:for-each>
</table>
</xsl:when>
<xsl:otherwise>
<!-- select each table in the section-->
<xsl:apply-templates select="./*[@Format='Table']"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="NVPair">
<tr>
<th><xsl:value-of select="name(.)</th>
<td><xsl:value-of select="."/></td>
</tr>
</xsl:template>
<xsl:template name="QATable" match="*[@Format='Table']">
<h4><xsl:value-of select="name(.)</h4>
<xsl:choose>
<xsl:when test="count(*) = 0">
<p>No Rows</p>
</xsl:when>
<xsl:otherwise>
<table class="QATable">
<thead>
<tr>
<xsl:for-each select="*[1]/*">
<td><xsl:value-of select="name(.)"/></td>
</xsl:for-each>
</tr>
</thead>
<xsl:for-each select="*">
<tr>
<xsl:for-each select="*">
<td><xsl:value-of select="."/></td>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
【问题讨论】: