XML+XSLT实现的人口金字塔图,效果如下:
XML示例数据(数据是我自己造的):
View Code
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="PopulationChart.xslt"?>
<DataSet>
<Data>
<Item Name="ID" Value="01">01</Item>
<Item Name="RowName" Value="0-4岁">0-4岁</Item>
<Item Name="Male" Value="20100">20100</Item>
<Item Name="Female" Value="18900">18900</Item>
</Data>
<Data>
<Item Name="ID" Value="02">02</Item>
<Item Name="RowName" Value="5-9岁">5-9岁</Item>
<Item Name="Male" Value="33400">33400</Item>
<Item Name="Female" Value="31000">31000</Item>
</Data>
<Data>
<Item Name="ID" Value="03">03</Item>
<Item Name="RowName" Value="10-14岁">10-14岁</Item>
<Item Name="Male" Value="53000">53000</Item>
<Item Name="Female" Value="48900">48900</Item>
</Data>
<Data>
<Item Name="ID" Value="04">04</Item>
<Item Name="RowName" Value="15-19岁">15-19岁</Item>
<Item Name="Male" Value="100600">100600</Item>
<Item Name="Female" Value="90010">90010</Item>
</Data>
<Data>
<Item Name="ID" Value="05">05</Item>
<Item Name="RowName" Value="20-24岁">20-24岁</Item>
<Item Name="Male" Value="170200">170200</Item>
<Item Name="Female" Value="161670">161670</Item>
</Data>
<Data>
<Item Name="ID" Value="06">06</Item>
<Item Name="RowName" Value="25-29岁">25-29岁</Item>
<Item Name="Male" Value="210570">210570</Item>
<Item Name="Female" Value="201290">201290</Item>
</Data>
<Data>
<Item Name="ID" Value="07">07</Item>
<Item Name="RowName" Value="30-34岁">30-34岁</Item>
<Item Name="Male" Value="206280">206280</Item>
<Item Name="Female" Value="199330">199330</Item>
</Data>
<Data>
<Item Name="ID" Value="08">08</Item>
<Item Name="RowName" Value="35-39岁">35-39岁</Item>
<Item Name="Male" Value="181230">181230</Item>
<Item Name="Female" Value="171003">171003</Item>
</Data>
<Data>
<Item Name="ID" Value="09">09</Item>
<Item Name="RowName" Value="40-44岁">40-44岁</Item>
<Item Name="Male" Value="160200">160200</Item>
<Item Name="Female" Value="151271">151271</Item>
</Data>
<Data>
<Item Name="ID" Value="10">10</Item>
<Item Name="RowName" Value="45-49岁">45-49岁</Item>
<Item Name="Male" Value="144000">144000</Item>
<Item Name="Female" Value="132842">132842</Item>
</Data>
<Data>
<Item Name="ID" Value="11">11</Item>
<Item Name="RowName" Value="50-54岁">50-54岁</Item>
<Item Name="Male" Value="110709">110709</Item>
<Item Name="Female" Value="118210">118210</Item>
</Data>
<Data>
<Item Name="ID" Value="12">12</Item>
<Item Name="RowName" Value="55-59岁">55-59岁</Item>
<Item Name="Male" Value="94050">94050</Item>
<Item Name="Female" Value="99580">99580</Item>
</Data>
<Data>
<Item Name="ID" Value="13">13</Item>
<Item Name="RowName" Value="60-64岁">60-64岁</Item>
<Item Name="Male" Value="70200">70200</Item>
<Item Name="Female" Value="80090">80090</Item>
</Data>
<Data>
<Item Name="ID" Value="14">14</Item>
<Item Name="RowName" Value="65-69岁">65-69岁</Item>
<Item Name="Male" Value="61007">61007</Item>
<Item Name="Female" Value="73210">73210</Item>
</Data>
<Data>
<Item Name="ID" Value="15">15</Item>
<Item Name="RowName" Value="70-74岁">70-74岁</Item>
<Item Name="Male" Value="56030">56030</Item>
<Item Name="Female" Value="61290">61290</Item>
</Data>
<Data>
<Item Name="ID" Value="16">16</Item>
<Item Name="RowName" Value="75-79岁">75-79岁</Item>
<Item Name="Male" Value="45140">45140</Item>
<Item Name="Female" Value="58101">58101</Item>
</Data>
<Data>
<Item Name="ID" Value="17">17</Item>
<Item Name="RowName" Value="80-84岁">80-84岁</Item>
<Item Name="Male" Value="39100">39100</Item>
<Item Name="Female" Value="44090">44090</Item>
</Data>
<Data>
<Item Name="ID" Value="18">18</Item>
<Item Name="RowName" Value="85-89岁">85-89岁</Item>
<Item Name="Male" Value="22100">22100</Item>
<Item Name="Female" Value="33820">33820</Item>
</Data>
<Data>
<Item Name="ID" Value="19">19</Item>
<Item Name="RowName" Value="90-94岁">90-94岁</Item>
<Item Name="Male" Value="990">990</Item>
<Item Name="Female" Value="980">980</Item>
</Data>
<Data>
<Item Name="ID" Value="20">20</Item>
<Item Name="RowName" Value="95-100岁">95-99岁</Item>
<Item Name="Male" Value="92">92</Item>
<Item Name="Female" Value="120">120</Item>
</Data>
<Data>
<Item Name="ID" Value="21">21</Item>
<Item Name="RowName" Value="100岁以上">100岁以上</Item>
<Item Name="Male" Value="97">97</Item>
<Item Name="Female" Value="110">110</Item>
</Data>
<Other>
<Caption>人口金字塔</Caption>
</Other>
</DataSet>
XSLT文件PopulationChart.xslt内容如下:
<?xml version="1.0" encoding="utf-8" ?>
<!--人口金字塔-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!--数据范围variable-->
<xsl:variable name="nodeSet" select="DataSet/Data/node()[@Name='Male' or @Name='Female']"/>
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>人口金字塔</title>
</head>
<body style="text-align:center;">
<div style="750px;text-align:center;margin:auto;padding:auto;">
<div style="border:1px gray solid;padding:10px 10px 10px 10px;750px;">
<div style="font-weight:bold;height:40px;">
<xsl:value-of select="DataSet/Other/Caption"/>
</div>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<!--调用Template求最大值 (XSLT1.0中无max函数)-->
<xsl:variable name="maxVal">
<xsl:call-template name="maxFunc">
<!--参数posVal,即节点position值,最小值为1)-->
<xsl:with-param name="posVal">1</xsl:with-param>
<!--参数endPosVal,即数据行数,使用variable(variable名前加$符号)-->
<xsl:with-param name="endPosVal" select="count($nodeSet)"/>
<!--参数result存放结果-->
<xsl:with-param name="result">0</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<xsl:for-each select="//DataSet/Data[count(node())>0]">
<xsl:sort select="Item[@Name='ID']" order="descending"/>
<xsl:variable name="male_divWidthVal" select="round((Item[@Name='Male'] div $maxVal)*200)"/>
<xsl:variable name="female_divWidthVal" select="round((Item[@Name='Female'] div $maxVal)*200)"/>
<tr>
<td style="padding-right:5px;text-align:right">
<!--坐标值(年龄段)-->
<xsl:value-of select="Item[@Name='RowName']"/>— 
</td>
<td style="7px;border-top:1px black solid;border-left:1px black solid;border-bottom:1px black solid;">
<!--坐标刻度-->
<xsl:if test="position()>1">
<xsl:attribute name="style"> 7px; border-left: 1px black solid; border-bottom: 1px black solid;</xsl:attribute>
</xsl:if>
 
</td>
<td style="text-align:right;">
<!--男性人数矩形条(左侧)-->
<xsl:choose>
<xsl:when test="$male_divWidthVal>=1">
<div style="{$male_divWidthVal}px; background-color: #00FF00;float:right;"> </div>
</xsl:when>
<xsl:when test="$male_divWidthVal>0 and $male_divWidthVal<1">
<div style="1px; background-color: #00FF00;float:right;"> </div>
</xsl:when>
<xsl:otherwise>
<div style="1px;float:right;"> </div>
</xsl:otherwise>
</xsl:choose>
<div style="float:right;">
<xsl:value-of select="Item[@Name='Male']"/>
</div>
</td>
<td style="text-align:left;">
<!--女性人数矩形条(右侧)-->
<xsl:choose>
<xsl:when test="$female_divWidthVal>=1">
<div style="{$female_divWidthVal}px; background-color: #FF0000;float:left;"> </div>
</xsl:when>
<xsl:when test="$female_divWidthVal>0 and $female_divWidthVal<1">
<div style="1px; background-color: #FF0000;float:left;"> </div>
</xsl:when>
<xsl:otherwise>
<div style="1px;float:left;"> </div>
</xsl:otherwise>
</xsl:choose>
<div style="float:left;">
<xsl:value-of select="Item[@Name='Female']"/>
</div>
</td>
</tr>
</xsl:for-each>
<tr>
<td>
 
</td>
<td>
 
</td>
<td style="text-align: center;" valign="middle">
<!--颜色说明-->
<span style="8px;height:8px;overflow:hidden; background-color: #00FF00;margin-bottom:6px;"> </span>男
</td>
<td style="text-align: center;" valign="middle">
<!--颜色说明-->
<span style="8px;height:8px;overflow:hidden; background-color: #FF0000;margin-bottom:6px;"> </span>女
</td>
</tr>
</table>
</div>
</div>
</body>
</html>
</xsl:template>
<!--XSLT1.0中使用template递归调用求最大值-->
<xsl:template name="maxFunc">
<xsl:param name="posVal"/>
<xsl:param name="endPosVal"/>
<xsl:param name="result"/>
<xsl:choose>
<xsl:when test="$endPosVal>$posVal">
<xsl:call-template name="maxFunc">
<xsl:with-param name="posVal" select="$posVal+1"/>
<xsl:with-param name="endPosVal" select="$endPosVal"/>
<xsl:with-param name="result">
<xsl:variable name="nodeVal" select="$nodeSet[$posVal]"/>
<xsl:choose>
<xsl:when test="$nodeVal>$result">
<xsl:value-of select="$nodeSet[$posVal]"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$result"/>
</xsl:otherwise>
</xsl:choose>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="nodeVal" select="$nodeSet[$posVal]"/>
<xsl:choose>
<xsl:when test="$nodeVal>$result">
<xsl:value-of select="$nodeSet[$posVal]"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$result"/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
最快的查看方法是将XML文件和XSLT文件放在同一个目录,用浏览器打开XML文件即可查看页面显示效果(chrome浏览器用文件形式看不了,需要以URL地址来查看)。
因为XML中的<?xml-stylesheet type="text/xsl" href="PopulationChart.xslt"?>这部分已经声明关联的XSLT文件。
也可以用VS的XSLT调试功能(如下图,具体操作之前的文章已经提到过),指定XSLT对应的XML文件之后调试或者直接得到对应的HTML。
另外,可以使用JS指定XSLT文件解析XML数据,得到HTML字符串;也可以在后台通过C#的XslCompiledTransform.Transform方法调用XSLT文件解析XML生成对应的HTML。