近来在做项目时需要将XML格式进行转换,于是便使用了XSLT来进行格式转换工作。
XSLT介绍
XSLT是一种将XML文档转换为其他文本文档的语言,是建立在XML和XPath之上的国际标准,内容比较多,功能强大。
对于编程人员来说,XSLT可以看作以前序遍历的方式专门处理XML树状结构的标记语言。以前编程根据XML文档输出纯文本数据时需要写代码以前序遍历方式的方式遍历XML文档对象组成的树状结构,对于每一个特定名称或特定层次的XML节点而输出不同的内容,这个过程比较复杂,代码量大,需用进行很多的状态判断。而XSLT则使用一种简洁明了的标记语言实现了相同的逻辑。因此XSLT从程序逻辑的角度看类似支持递归的编程语言,而且是专门处理XML文档的。
XSLT转换过程会涉及到三个文本文档,一个是要处理的原始XML文档,第二个就是XSLT样式表文档,该文档包含了XSLT代码,XSLT代码本身就是XML格式,但使用了XML的名称空间。第三个就是XSLT处理输出的文本文档,注意,此处输出的是纯文本文档,这个文档具体是什么格式完全靠XSLT代码来决定,可以是另外一个XML文档,HTML文档,SQL语句字符串或者其他任意格式的字符串数据等等,XSLT转换只能输出纯文本文档,此外就没有限制输出文档的具体格式。
数据XML文档是一个很简单的XML文档,此处不加说明了。重点说说XSLT样式表文档,XSLT样式表文档本身是一个XML文档。它采用XML的树状结构来描述递归处理过程,也比较好理解。
在样式表文档中,根元素为 xsl:stylesheet ,里面定义了一个名为xsl的名称空间,这个根节点及其属性值都是固定的。
xsl:output 元素是可选的,它的method属性用于指定输出文档的格式,可以设置为xml,html或text值。此处使用xml输出样式,说明输出的文档是XML格式的,XSLT转换会尽量生成XML文档,但不作保证,因此仍然有可能生成不合格的XML文档。
xsl:template 用于定义一个XSLT模板,模板类似编程语言中的函数,可实现XSLT代码的重用。模板可以使用name属性定义名称,也可以使用match属性定义匹配的XPath路径,这个模板使用了match属性来匹配XML文档本身。
然后是 html 元素,由于html元素没有使用xsl的前缀,因此不属于xslt代码,因此将原样输出,跟着后面的body,table元素也是一样的。
xsl:for-each 元素类似C#中的foreach 语法结果,表示循环遍历元素,它使用select属性指定一个XPath相对路径,XSLT使用这个相对路径查询所有要遍历的XML节点,此时当前节点就是XML文档本身,因此XSLT处理器会调用XmlDocument的SelectNodes 函数来获得要遍历的XML节点,函数的参数就是Table/Record。于是我们开始循环遍历所有的Record元素了。
在循环遍历Record元素时,对每一个Record元素都要输出xsl:for-each的子节点,首先是 tr 元素,这不是XSLT元素,因此原样输出。这里还套嵌定义了另外一个for-each元素,于是我们又开始了一个新的循环遍历了,新的循环指定的相对XPath路径是一个星号,表示匹配所有名称的子元素,这类似DOS命令Dir中使用星号匹配所有文件。此处表示循环遍历Record元素下面所有的字段元素。
对每一个字段元素,首先输出td 元素,然后处理xsl:value-of 元素,xsl:value-of 表示输出指定相对路径的节点的值,这里指定的XPath是一个点号,表示当前节点本身,由于当前节点是XML元素,因此也就输出元素的文本内容,相当于输出XmlElement的InnerText 属性值。
xslt文件:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
<xsl:output method="xml" indent="yes" encoding="utf-8"/>
<xsl:template match="/">
<xsl:for-each select="Category">
<Category>
<xsl:attribute name="Navigate">
<xsl:value-of select="@Navigate"/>
</xsl:attribute>
<xsl:element name="Name">
<xsl:value-of select="Name"/>
</xsl:element>
<xsl:element name="EngName">
<xsl:value-of select="EngName"/>
</xsl:element>
<xsl:element name="ChtName">
<xsl:value-of select="ChtName"/>
</xsl:element>
<xsl:element name="Description">
<xsl:value-of select="Description"/>
</xsl:element>
<xsl:element name="EngDescription">
<xsl:value-of select="EngDescription"/>
</xsl:element>
<xsl:element name="ChtDescription">
<xsl:value-of select="ChtDescription"/>
</xsl:element>
<xsl:element name="Editor">
<xsl:value-of select="Editor"/>
</xsl:element>
<xsl:element name="LastModified">
<xsl:value-of select="LastModified"/>
</xsl:element>
<xsl:element name="Identity">
<xsl:text>CAT_ZTF</xsl:text>
</xsl:element>
<xsl:element name="Notes">
<xsl:value-of select="Notes"/>
</xsl:element>
<xsl:element name="TotalCount">
<xsl:text>{0}</xsl:text>
</xsl:element>
<xsl:for-each select="Content">
<xsl:for-each select="CatItem">
<xsl:element name="CatItem">
<xsl:attribute name="Name">
<xsl:value-of select="@Name"/>
</xsl:attribute>
<xsl:attribute name="Code">
<xsl:value-of select="@Code"/>
</xsl:attribute>
<xsl:attribute name="ParentCode">
<xsl:value-of select="@ParentCode"/>
</xsl:attribute>
<xsl:attribute name="CategoryType">
<xsl:text>CAT_ZTF</xsl:text>
</xsl:attribute>
</xsl:element>
</xsl:for-each>
</xsl:for-each>
</Category>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
原XML文件:
<?xml version="1.0" encoding="GB2312"?>
<Category Navigate="1">
<Name>专用分类</Name>
<EngName>New</EngName>
<ChtName>專用分類</ChtName>
<Description/>
<EngDescription/>
<ChtDescription/>
<Editor>Liangying</Editor>
<LastModified>2010-5-31</LastModified>
<Identity>CAT_XXXX</Identity>
<Notes>专用分类</Notes>
<Content Count="97">
<CatItem Name="文艺" Description="" EngDescription="" ChtDescription="" Code="001" ParentCode="" Nav="tttt?={0}"/>
<CatItem Name="小说" Description="" EngDescription="" ChtDescription="" Code="001001" ParentCode="001" Nav="tttt?={0}"/>
<CatItem Name="文学" Description="" EngDescription="" ChtDescription="" Code="001002" ParentCode="001" Nav="tttt?={0}"/>
<CatItem Name="散文" Description="" EngDescription="" ChtDescription="" Code="001003" ParentCode="001" Nav="tttt?={0}"/>
</Content>
</Category>
转换C#代码:
/// </summary>
/// <param name="strXmlPath"></param>
/// <param name="strXsltPath"></param>
/// <returns></returns>
public string TransferXmlByXSLT(string strXmlPath,string strXsltPath)
{
MemoryStream fs = new MemoryStream();
string outputstring = string.Empty;
try
{
//判断文件是否存在
if (File.Exists(Server.MapPath(strXmlPath)) && File.Exists(Server.MapPath(strXsltPath)))
{
//加载xml文件
XPathDocument doc = new XPathDocument(strXmlPath);
XslTransform transForm = new XslTransform();
//加载xslt文件
transForm.Load(strXsltPath);
XPathNavigator nav = doc.CreateNavigator();
//转换xml
transForm.Transform(nav, null, fs);
fs.Seek(0, SeekOrigin.Begin);
StreamReader stream = new StreamReader(fs);
outputstring = stream.ReadToEnd();
fs.Close();
fs.Dispose();
}
else
{
return "";
}
}
finally
{
fs.Close();
fs.Dispose();
}
return outputstring;
}
转换后的XML:
<?xml version="1.0" encoding="GB2312"?>
<Category Navigate="1">
<Name>专用分类</Name>
<EngName>New</EngName>
<ChtName>專用分類</ChtName>
<Description/>
<EngDescription/>
<ChtDescription/>
<Editor>Liangying</Editor>
<LastModified>2010-5-31</LastModified>
<Identity>CAT_XXXX</Identity>
<Notes>专用分类</Notes>
<TotalCount>{0}</TotalCount>
<CatItem Name="文艺" Code="001" CategoryType="CAT_ZTF" ParentCode="" />
<CatItem Name="小说" Code="001001" CategoryType="CAT_ZTF" ParentCode="001" />
<CatItem Name="文学" Code="001002" CategoryType="CAT_ZTF" ParentCode="001" />
<CatItem Name="散文" Code="001003" CategoryType="CAT_ZTF" ParentCode="001" />
</Category>