在.Net中使用msxsl:script脚本块扩展XSLT的具体实践与应用

214 views 0 comments posted at about 8 years ago Raymond Tang

一概述

XSLT可以用于将XML格式的数据转换为其它格式,在数据和展示分开以及数据相互转换中可以得到广泛的应用,比较典型的是以前的动网论坛模板系统以及动易的标签系统。掌握好XSLT可以灵活的处理XML,同时运用在Web应用程序中也非常的方便,不过缺点是使用者需要掌握大量的XPath、XSLT、XML等相关知识。

在XSLT中,可以直接使用脚本语言如Javascript输出到Html中,进行相关的客户端操作,由于一些限制,XSLT提供的函数可能不能达到一些复杂的数据处理效果,这个时候就需要使用扩展脚本块的功能,这样就可以使用C#等强类型的语言进行相关的数据处理工作。

在.Net中可以进行XSLT转换功能的类是XslCompiledTransform ,具体参考msdn.microsoft.com/zh-tw/library/system.xml.xsl.xslcompiledtransform(zh-cn).aspx

关于本文叙述的内容可以参考http://msdn.microsoft.com/zh-tw/library/wxaw5z5e(zh-cn).aspx

关于Xslt以及XPath可在网上参考相关文档。

二实现msxsl:script的功能

下面举一个例子实现该功能

1,新建一Web应用程序项目

2,在项目中添加一个Xml文件News.xml,内容如下:

<?xml version="1.0" encoding="utf-8" ?>
<AllNews>
<News Author="Raymond">
    <Title>测试新闻标题1test test</Title>
    <Content>这里是新闻的内容...</Content>
</News>
<News Author="Jack">
    <Title>测试新闻标题2 test test test</Title>
    <Content>这里是新闻的内容...</Content>
</News>
<News Author="Tom">
    <Title>测试新闻标题3 test test test test</Title>
    <Content>这里是新闻的内容...</Content>
</News>
</AllNews>

3,新建一个Xslt文件News.xslt,用于将Xml转换为Html内容如下:

<?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="html" indent="yes"/>

    <xsl:template match="/">
      <xsl:call-template name="style"/>
      <xsl:call-template name="showNews">
        <xsl:with-param name="news" select="AllNews/News"/>
      </xsl:call-template>
    </xsl:template>

<xsl:template name="style">
    <style>
      .title{font-size:14px;font-weight:bold;color:White;background-color:#000000;}
      div.newsBlock{border:1px dashed #000000;padding:5px;margin-bottom:10px;background-color:Gray;}
      div.content{text-indent:2em;}
    </style>
</xsl:template>

<!--展示新闻-->
<xsl:template name="showNews">
    <xsl:param name="news"/>
    <xsl:for-each select="$news">
      <div class="newsBlock">
        <div class="title">
          <xsl:value-of select="Title"/>
        </div>
        <div class="content">
          <xsl:value-of select="Content"/>(<xsl:value-of select="@Author"/>)
        </div>
      </div>
    </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

4,在Web项目的Default.aspx.cs中添加解析Xml的代码并且输出

添加代码如下:

protected void Page_Load(object sender, EventArgs e)
        {
            this.ShowNews();
        }

        /// <summary>
        /// 转换Xml并且显示新闻
        /// </summary>
        private void ShowNews()
        {
            //实例化
            XslCompiledTransform transform = new XslCompiledTransform();
            //加载样式表
            transform.Load(Server.MapPath("News.xslt"));
            //转换并且输出
            transform.Transform(Server.MapPath("News.xml"), null, Response.OutputStream);
        }

浏览Default.aspx 我们可以看到效果如下:

这样数据就正确的显示出来了

5,添加脚本块

我们试想一种情况,Xml中的一些数据可能通过xslt的函数无法处理那么这个时候我们需要借助于其他语言进行处理,这个时候我们可以考虑使用扩展脚本块来实现。

这里举一个例子,我们将新闻的标题仅显示前边7个字符,我们通过扩展的C#函数来处理(当然直接通过xslt的substring可以直接处理,这里仅举例而已,在一些情况下xslt自带函数无法实现很多跟业务逻辑层、数据层等相关的操作的情况下可以使用此方法)。

5.1,新建一个类库项目AssemblyTest

添加类XsltTest

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AssemblyTest
{
    public class XsltTest
    {
        /// <summary>
        /// 返回缩减的标题
        /// </summary>
        /// <param name="title"></param>
        /// <returns></returns>
        public static string GetTitle(string title)
        {
            return title.Substring(0, 7);
        }
    }
}

5.2在Web应用程序中添加对AssemblyTest类库项目的引用

5.3修改News.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"
xmlns:pl="http://www.polarlight.net/xslt/example">

<msxsl:script language="C#" implements-prefix="pl">
    <msxsl:assembly name="AssemblyTest"/>
    <msxsl:using namespace="AssemblyTest"/>
    <![CDATA[
public static string GetTitle(string title)
        {
            return AssemblyTest.XsltTest.GetTitle(title);
        }
]]>
</msxsl:script>

<xsl:output method="html" indent="yes"/>

<xsl:template match="/">
    <xsl:call-template name="style"/>
    <xsl:call-template name="showNews">
      <xsl:with-param name="news" select="AllNews/News"/>
    </xsl:call-template>
</xsl:template>

<xsl:template name="style">
    <style>
      .title{font-size:14px;font-weight:bold;color:White;background-color:#000000;}
      div.newsBlock{border:1px dashed #000000;padding:5px;margin-bottom:10px;background-color:Gray;}
      div.content{text-indent:2em;}
    </style>
</xsl:template>

<!--展示新闻-->
<xsl:template name="showNews">
    <xsl:param name="news"/>
    <xsl:for-each select="$news">
      <div class="newsBlock">
        <div class="title">
          <xsl:value-of select="pl:GetTitle(Title)"/>
        </div>
        <div class="content">
          <xsl:value-of select="Content"/>(<xsl:value-of select="@Author"/>)
        </div>
      </div>
    </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

请大家留意上面红色部分,并思考为什么要这样做

5.4再次打开Default.aspx,这个时候我们可以看到也没抛出以下异常:

禁止执行脚本。使用 XsltSettings.EnableScript 属性可以启用。 D:\Users\Administrator\Documents\Visual Studio 2008\Projects\ConsoleTest\WebApplicationTest\News.xslt(40,11) 处出错

这个时候我们还需要对Default.aspx.cs的内容,允许执行脚本

5.5修改Default.aspx.cs的ShowNews方法为:

/// <summary>
        /// 转换Xml并且显示新闻
        /// </summary>
        private void ShowNews()
        {
            //实例化
            XslCompiledTransform transform = new XslCompiledTransform();
            //加载样式表 new XsltSettings(false, true)第二个参数允许执行脚本
            transform.Load(Server.MapPath("News.xslt"), new XsltSettings(false, true), null);

            //转换并且输出
            transform.Transform(Server.MapPath("News.xml"), null, Response.OutputStream);
        }
5.6重新生成项目,这个时候浏览Default.aspx就可以看到如下效果:


三延伸扩展

通过以上例子我们可以看到配合msxsl:script我们可以用强类型的语言如C#来处理xml数据。动易的标签系统如pe:GetNode等其实就是通过这种方法来实现的,并没有任何复杂的技术。

1,使用.Net的控件通过xslt转换xml为html

除了上述方法以外,我们可以使用.Net自带的控件来显示Xml数据,如XmlDataSource

在Default.aspx中添加相关控件

<asp:XmlDataSource ID="XmlDataSource1" runat="server" DataFile="~/News.xml" XPath="/AllNews/News"></asp:XmlDataSource>
        <br />
        <style>
            .title
            {
                font-size: 14px;
                font-weight: bold;
                color: White;
                background-color: #000000;
            }
            div.newsBlock
            {
                border: 1px dashed #000000;
                padding: 5px;
                margin-bottom: 10px;
                background-color: Gray;
            }
            div.content
            {
                text-indent: 2em;
            }
        </style>
        <asp:Repeater ID="Repeater1" runat="server" DataSourceID="XmlDataSource1">
            <HeaderTemplate>
                通过控件直接显示:
            </HeaderTemplate>
            <ItemTemplate>
                <div class="newsBlock">
                    <div class="title">
                        <%#XPath("Title") %>
                    </div>
                    <div class="content">
                        <%#XPath("Content") %>
                        (<%#XPath("@Author") %>)
                    </div>
                </div>
            </ItemTemplate>
        </asp:Repeater>

再次打开Default.aspx页面我们可以看到同样的效果:


2,通过xslt转换Xml为Html只是一种转换方式,还可以转换为其它格式的Xml或者文本,这在一个xml用于不同程序不同xml架构中尤其有用。

3,利用xslt+xml可以实现一些扩展性很强、灵活性强的应用,缺点就是需要掌握Xpath和Xml相关知识。

4,允许执行脚本块会带来一定的安全风险比如被黑客篡改脚本块C#的内容,执行一些非法操作,所以在使用的时候应小心谨慎。

5,Xslt中的数据类型与CLR对应关系:

为函数提供的参数和返回值可以是任意类型。 因为 W3C XPath 类型是公共语言运行库 (CLR) 类型的子集,所以,对不属于 XPath 类型的类型进行类型转换。 下表显示相应的 W3C 类型和等效的 CLR 类型。

W3C 类型

CLR 类型

String

String

Boolean

Boolean

Number

Double

Result Tree Fragment

XPathNavigator

Node Set

XPathNodeIterator

CLR 数字类型转换为 DoubleDateTime 类型转换为 StringIXPathNavigable 类型转换为 XPathNavigatorXPathNavigator[] 转换为 XPathNodeIterator

所有其他类型均将引发错误。

Add comment

Comments (0)

No comments yet.
In this Page