Rocho.J

人脑是不可靠的, 随时记录感悟并且经常重复!

 

学习笔记 --- XML、生成Excel、XML加密解密

今天本来想整理下ASP.NET MVC, 做个增删改查的Demo. 可是, 又不想去动数据库, 于是想到了XML. 可是, 突然发现对XML的认识和了解还不够系统, 无奈先整理下XML吧! %>_<%!!!!!!!!!!!!!!!!!!!

一、 XML

XML(eXtensible Markup Language, 扩展标记语言), 是W3C(WWW Confederation, 万维网联盟)认可的文档标记标准. XML是用来描述数据的一种格式, 这种格式使用简单, 可以用来描述无穷无尽的类型的数据.

关于XML的历史, XML源自IBM的SGML(Standard Generalized Markup Language, 标准通用标记语言), …… 如是云云.

XML默认的版本号为1.0, 默认编码方式为UTF-8. 这在XML文件的指令中给出, 如:

<?xml version=”1.0” encoding=”UTF-8”?>. 关于XML的基础知识, 可以看随后贴出的Xml Schema示例.

XML Schema是用来规范XML格式的, 也就是说XML是一种描述数据的格式, 而Xml Schema是规范并检查Xml格式的. 通俗点说就是: 我们用XML描述了一堆数据, 但是不同的人有不同的思考角度, 如是乎就有了很多种不同的数据描述, 那么程序是固定的, 我们可以用XML Schema来约定只有符合Schema约定的数据描述XML文件才是可用的. 用来约定XML的有两种, 一种是XML Schema, 一种是DTD(Document Type Definition, 文档类型定义), 后者在HTML领域用的多, 在XML领域还是Schema吧.

我们如何来获得XML中的数据呢? 使用XPath, XPath相当于数据库中的Select语句, 可以看做是XML中的Select语句.

关于XPath的基础知识, 看接下的Xml Schema的示例.

值得一提的是, XSL(eXtensible Stylesheet Language, 扩展样式表语言)是一种脚本语言, 可以用来将XML文档转换成其他的文档格式, 如html. 这种转化过程叫做XSLT(XSL – Transformation, xsl转换), 这个脚本语言是一种专门的语言, 应用的话也不是没有, 但是不多, 等需要的时候在看吧.

Xml Schema示例:

//XMLOperation.xml

代码
<?xml version="1.0" encoding="UTF-8"?>
<!-- XML基础知识概述:

1. 字符编码:
ASCII码常见字符: Tab -> 9、回车换行(\r\n) -> 13 10、空格 -> 32、0 -> 48、A -> 65、a -> 97
GB2312采用双字节存储汉字: 首字节在0-127表示英文, >127将联合下一个字节表示汉字.
文件头: Unicode(FF FE)、Unicode-big-endian(FE FF)、UTF-8(EF BB BF). 计算机内部采用Unicode编码, 传输和保存时采用UTF-8编码, 若没有文件头, 则默认采用UTF-8编码.
字符编码的类Encoding的三个重要方法: GetEncoding()、GetBytes()和GetChars()

2. XML仅仅是描述数据的格式, 而XML Schema是用来定义XML的规范, 即检查XML文件是否符合Schema的规定.
注意事项: XML区分大小写、属性需用引号括起来且不区分单双引号.
XML的元素(8种):
a. XML的定义: 如: <?xml version="1.0" encoding="GB2312"?>
b. 元素: <author>张三</author>, 空元素可以简写为</author>
c. 属性: <book code="1234"></book>, code为属性, 多个属性一空格分隔.
d. 文本内容: 如上边的张三. 可以使用&#十进制;和&#x十六进制;表示字符编码表上的对应字符, &#1968;别忘记分号.
e. 实体参考: 类似于特殊符号的转义. 如: (&lt;、&gt;、&amp;、&quot;、&apos;)分别表示<、>、&、"、', 分号不能省.对应英文为: less than、greater than、ampersand、quotation、apostrophe. 例如: &amp;表示为&amp;amp;
f. 注释: 本段最外层即为注释
g. CDATA: 即字符数据Character Data, 也就是不需要XML解析的内容, 如: <![CDATA[...内容...]]>
h. PI处理指令: 如<?指令名 指令内容?>, 如第一行, xml是指令名, 后便的为指令值, 且可以有多个值. 如:<?xml-stylesheet type="text/xsl" href="book.xslt"?>

3. Xml Schema:
示例: <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns1="aspnet" targetNamespace="aspnet" elementFormDefault="qualified" attributeFormDefault="unqualified"></xs:schema>
a. xs:schema表示xs前缀(prefix)代表的命名空间下的schema根元素; xmlns:xs="..."表示xml namespace(xmlns)命名空间, xs是命名空间的代号, 它指代=号后边的内容, 此外还可以为schema中的元素及属性设置(attribute)不同的命名空间, 这样在不同的命名空间中, 可以使用相同的元素名. 例如: 上例中的xmlns:ns1="..."中ns1代表=号后内容的, targetNamespace表示目标命名空间, 即定义的命名空间. elementFormDefault="qualified"表示元素默认需要写出命名空间如: xs、ns1, attributeFormDefault="unqualified"表示属性可以不写命名空间, 默认与元素的命名空间相同.
b. XmlSchema只有两种数据类型: 简单类型(不包含子元素和属性), 复杂类型(包含子元素或属性). 若是复杂类型必须用<complexType>标记, 若复杂类型包含子元素则必须用<sequence>表示子元素的顺序.
c. type属性用来表示简单元素的类型: xs:string、xs:integer、xd:boolean, 注意XML没有char类型.
d. 通过ref可以直接将元素指向另一个模块, 从而简化schema的复杂度.
e. 元素属性(attribute)的定义需要先定义子元素(与<sequence>并列且在<squence>下面), 然后在定义元素的属性. 可用空的<sequence></sequence>表示空元素.
f. 可以使用<choise>定义从n个子元素中选择1个元素.
g. 可以用minOccurs和maxOccurs来定义子元素的数量范围(可为0), 可以使用default设置默认值.
h. 可以使用<enumeration value="...">列举可选的值, 使用<minInclusive value="...">和<maxInclusive value="...">确定取值范围.
i: 使用use表示是否为必须存在的属性, required必须、optional可选、prohibited无属性的值
j: 可以采用<attributeGroup>重新改写复杂元素的属性

4. XPath: 用来获取XML中的元素
路径: / 根、 绝度路径(从/开始的路径)、相对路径(不从/开始的短路径)、圆点表示当前节点、两个圆点表示上一个节点
相对路径: 找到上级元素后, 点击"I"型按钮设置相对路径, 之后就可以直接找子元素了
元素名: 如: /configuration/system.web/httpHandlers/add, add表示所有的匹配元素
属性名: 用@属性名获取属性值, 如: @validate
函数: 通过函数取得节点内容, 常见函数: text()、comment()、processing-instruction(), 如: /configuration/appSettings/text()和/configuration/system.web/httpHandlers/comment()
处理节点的函数: 当前节点序号position()、当前上下文节点数last()、参数的节点数count()、返回具有指定id的节点集合id()、第一个节点的本地名local-name()、第一个节点的名称空间namespace-uri()、第一个节点的带前缀的名称name
字符串函数: string()、start-with()、contains()、第一次匹配之前的串substring-before()、第一次匹配之后的串substring-after()、substring()、string-length()、格式化元素中的空白normalize-space()
//和|: //表示从所有的后代中匹配, |用于合并匹配的结果, 如: //configuration/system.web/httpHandlers/add/(@verb | @validate
通配符: *(匹配任意节点, 不含属性、文本、注释及处理指令)、node()(匹配所有的节点, 含属性、文本、注释等)、@*(匹配所有的属性节点), 例如: 通配符: *(匹配任意节点, 不含属性、文本、注释及处理指令)、node()(匹配所有的节点, 含属性、文本、注释等)、@*(匹配所有的属性节点), 例如: //configuration/system.web/httpHandlers/add/@*
[@属性名="..."]: 类似于Sql中的where, 如: /configuration/system.web/httpHandlers/add [@verb="GET,POST"]/@validate, 找到verb=get,post的add元素的validate值

###############################示例如下##################################
-->
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<appSettings> web.config不好找简单类型, 就暂且拿这个当个简单类型吧! </appSettings>
<connectionStrings>
<add name="calendar" connectionString="server=192.168.0.67\.;database=calendar;integrated security=true;"/>
</connectionStrings>
<system.codedom>
<compilers>
<compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<providerOption name="CompilerVersion" value="v3.5"/>
<providerOption name="WarnAsError" value="false"/>
</compiler>
<compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" warningLevel="4" type="Microsoft.VisualBasic.VBCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<providerOption name="CompilerVersion" value="v3.5"/>
<providerOption name="OptionInfer" value="true"/>
<providerOption name="WarnAsError" value="false"/>
</compiler>
</compilers>
</system.codedom>
<system.web>
<httpHandlers>
<cellphone>1398-371-9899</cellphone>
<!--新加的简单类型! -->
<salary amount="4000"/>
<remove verb="*" path="*.asmx"/>
<add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add verb="GET,POST" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/>
</httpHandlers>
</system.web>
</configuration>

//XMLOperation.xsd

代码
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">

<xs:element name="configuration">
<!--复杂类型一定有子元素或者属性, 只要是复杂类型, 写个名就往里分-->
<xs:complexType>
<!--先写子元素, 后写属性, 且子元素需要说明其顺序-->
<xs:sequence>
<!--简单类型无子元素也无属性, 不再往里分了, 指定数据类型结束-->
<xs:element name="appSettings" type="xs:string" maxOccurs="1" minOccurs="0"/>
<xs:element name="connectionStrings" maxOccurs="1" minOccurs="0"><!--原始写法-->
<xs:complexType>
<xs:sequence>
<xs:element name="add">
<xs:complexType>
<!--只有属性, 没有子元素-->
<xs:attribute name="name" type="xs:string" use="required"/>
<xs:attribute name="connectionString" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="system.codedom"><!--原始写法-->
<xs:complexType>
<xs:sequence>
<xs:element name="compilers">
<xs:complexType>
<xs:sequence>
<xs:element name="compiler" minOccurs="1" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="providerOption" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="name" type="xs:string" use="required"/>
<xs:attribute name="value" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="language" type="xs:string" use="required"/>
<xs:attribute name="extension" type="xs:string" use="required"/>
<xs:attribute name="warningLevel" type="xs:integer" use="required"/>
<xs:attribute name="type" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="system.web"><!--通过ref简化schema-->
<xs:complexType>
<xs:sequence>
<xs:element ref="httpHandlers" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<!--sequence之后写属性, 属性不再往里分了, 制定数据类型结束-->
</xs:complexType>
</xs:element >

<xs:element name="httpHandlers">
<xs:complexType>
<xs:sequence>
<xs:choice><!--使用choice从n个子元素中选择一个-->
<xs:element name="cellphone" type="customizeType"/><!--使用自定义简单类型, 使用正则表达式-->
<xs:element name="email" type="xs:string"/>
<xs:element name="telphone" type="xs:string"/>
</xs:choice>
<xs:element name="salary"><!--使用minInclusive和maxInclusive限定范围-->
<xs:complexType>
<xs:attribute name="amount" type="amountType"/>
</xs:complexType>
</xs:element>
<xs:element name="remove" minOccurs="0" maxOccurs="1"><!--使用attributeGroup属性组-->
<xs:complexType>
<xs:attributeGroup ref="removeAttributes"></xs:attributeGroup>
</xs:complexType>
</xs:element>
<xs:element ref="add" minOccurs="1" maxOccurs="unbounded"/><!--使用ref简化复杂度-->
</xs:sequence>
</xs:complexType>
</xs:element>

<xs:element name="add"><!--使用ref简化复杂度, 使用enumeration获得允许的属性值-->
<xs:complexType>
<xs:attribute name="verb" type="enumVerbType" use="required"/>
<xs:attribute name="path" type="xs:string" use="required"/>
<xs:attribute name="validate" type="xs:boolean" use="optional"/>
<xs:attribute name="type" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>

<xs:attributeGroup name="removeAttributes"><!--使用attributeGroup属性组, 使用default默认值-->
<xs:attribute name="verb" type="xs:string" use="optional" default="*"/>
<xs:attribute name="path" type="xs:string" use="required"/>
</xs:attributeGroup>

<xs:simpleType name="customizeType"><!--使用正则表达式-->
<xs:restriction base="xs:string">
<xs:pattern value="\d{4}-\d{3}-\d{4}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumVerbType"><!--使用enumeration获得允许的属性值-->
<xs:restriction base="xs:string">
<xs:enumeration value="*"/>
<xs:enumeration value="GET"/>
<xs:enumeration value="POST"/>
<xs:enumeration value="GET,POST"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="amountType"><!--使用minInclusive和maxInclusive限定范围-->
<xs:restriction base="xs:integer">
<xs:minInclusive value="3000"/>
<xs:maxInclusive value="7000"/>
</xs:restriction>
</xs:simpleType>

</xs:schema>

接下来, 才是我们程序员最关心的事情, 如何在程序中读写XML文档.

为了能够在开发过程中使用XML, W3C指定了DOM规范, 即Document Object Model, 文档对象模型. DOM可以看做是XML或HTML文件在内存中的表示, 它是一个树形结构, document节点永远是这棵树的根节点. 在.NET中, System.Xml命名空间下定义了处理XML的类型. XmlNode为所有节点的基类, 其他节点类型直接或间接派生自XmlNode, 如下图:

如上图所示, 我们有3中方式操作XML文档, 3中方式各有优缺点.

建议的方式: 使用XPathDocument进行查询操作, 使用XML流进行一次性的创建和读取操作, 使用XPath进行修改操作.

详见示例:

读取的xml文件和xsd文件, 就是上例中的XMLOperation.xml和XMLOperation.xsd文件.

//Program.cs

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

namespace XMLDemo
{
class Program
{
staticvoid Main(string[] args)
{
#region 使用文本对象模型DOM(Document Object Model)和XPath操作XML, 缺点: 全部读到内存中, 消耗内存且较慢;
/*
//1. 创建读写XML的document对象
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();

//2. 读取XML
doc.Load("XMLOperation.xml");

//3. 处理
#region 使用Node获取信息, 数节点方式
Console.WriteLine("---------------XML节点文本-----------------");
System.Xml.XmlElement root = doc.DocumentElement; //获取根元素
System.Xml.XmlText text = root.ChildNodes[3].ChildNodes[0].ChildNodes[0].ChildNodes[0] as System.Xml.XmlText; //text内容被看做是单独的子节点
Console.WriteLine(text.Value);
#endregion

#region 使用XPath获取信息
Console.WriteLine("---------------XPath获得文本及属性值-----------------");
string xpath = "/configuration/system.web/httpHandlers/add"; //反斜杠不用转义, 通过XMLSpy获得xpath
System.Xml.XmlNodeList nodes = doc.SelectNodes(xpath);
foreach (System.Xml.XmlNode node in nodes)
{
Console.WriteLine(string.Format("add元素name={0}, validate={1}", node.Attributes["verb"].Value, node.Attributes["validate"].Value));
}
Console.WriteLine("------XPath获得文本, 文本内容当作节点处理------");
xpath = "/configuration/system.web/httpHandlers/cellphone";
text = doc.SelectSingleNode(xpath).ChildNodes[0] as System.Xml.XmlText; //文本内容当作一个节点
Console.WriteLine(text.Value);
Console.WriteLine("------------修改dom对象--------------");
text.Value = "xxxx";
Console.WriteLine(text.Value);
Console.WriteLine("------------创建dom元素对象--------------");
//创建一个节点
System.Xml.XmlElement newelem = doc.CreateElement("name");
System.Xml.XmlText newelemtext = doc.CreateTextNode("这里写名字! "); //要插入的文本节点内容
newelem.AppendChild(newelemtext);
newelem.SetAttribute("id", "001"); //直接通过SetAttribute设置属性
//获取要插入的节点
System.Xml.XmlElement oldelem = doc.SelectSingleNode("/configuration/system.web/httpHandlers") as System.Xml.XmlElement;
oldelem.AppendChild(newelem);
Console.WriteLine("插入完毕! ");
Console.WriteLine("------------删除dom对象--------------");
//查找要删除的节点, 并获得其父节点
System.Xml.XmlNode delNode = doc.SelectSingleNode("/configuration/system.web/httpHandlers/salary");
System.Xml.XmlNode parenNode = delNode.ParentNode;
parenNode.RemoveChild(delNode);
Console.WriteLine("删除完毕! ");
#endregion

//4. 写入XML
Console.WriteLine("----------------XML内容--------------------");
doc.Save(Console.Out); //输出到控制台

*/
#endregion

#region 使用XML流处理, 每次只处理一个节点, 速度快, 但缺点是: 不支持结构化查询, 适合从头到尾一次性处理
/*
System.IO.Stream fs = new System.IO.FileStream("XMLOperation.xsd", System.IO.FileMode.Open, System.IO.FileAccess.Read); //读的是xsd

//设置读取Xml时的Schema, 确保数据能正确读取(Schema)
System.Xml.Schema.XmlSchema schema = System.Xml.Schema.XmlSchema.Read(fs, new System.Xml.Schema.ValidationEventHandler(dealSchemaValidation));
Console.WriteLine("-------------Schema读取完毕---------------");

//配置Xml读取设置, 用来验证xml(xml)
System.Xml.XmlReaderSettings settings = new System.Xml.XmlReaderSettings();
settings.Schemas.Add(schema); //添加Schema到Schemas集合, 同一个XML可由多个schema验证
settings.ValidationType = System.Xml.ValidationType.Schema; //设置验证方式
settings.ValidationEventHandler += new System.Xml.Schema.ValidationEventHandler(dealSchemaValidation); //设置验证事件处理器
//使用XmlReader读取XML, 验证过程在读取的时候执行. 也可以单独用XmlReader配合空While读一遍Xml文件进行验证
using (System.Xml.XmlReader xmlreader = System.Xml.XmlReader.Create("XMLOperation.xml", settings)) //通过XmlReader的工厂方法获得XmlReader流适合读取
{
Console.WriteLine("输出xml中的所有属性: ");
while (xmlreader.Read())
{
if (xmlreader.NodeType == System.Xml.XmlNodeType.Element)
{
if (xmlreader.HasAttributes)
{
for (int i = 0; i < xmlreader.AttributeCount; i++)
{
xmlreader.MoveToAttribute(i); //移动到属性的位置
Console.WriteLine("属性名:{0}, 类型:{1}, 属性值:{2}", xmlreader.Name, xmlreader.ValueType, xmlreader.Value); //xmlreader.LocalName不带命名空间
}
}
//Console.WriteLine("InnerXml: " + xmlreader.ReadInnerXml());
//Console.WriteLine("OuterXml: " + xmlreader.ReadOuterXml());
//读取cellphone元素
//if (xmlreader.ReadToFollowing("cellphone"))
//{
// Console.WriteLine(xmlreader.ReadElementString("cellphone")); //读取cellphone元素的文本
//}
}
}
Console.WriteLine("验证完毕! ");
}
//使用xml流输出字符
using (System.Xml.XmlWriter xmlwriter = System.Xml.XmlWriter.Create("Output.xml"))
{
xmlwriter.WriteStartDocument();
xmlwriter.WriteStartElement("human"); //</humen>
xmlwriter.WriteStartElement("man"); //子元素
//写元素属性
xmlwriter.WriteAttributeString("name", "father"); //属性
xmlwriter.WriteString("Mike"); //文本区
xmlwriter.WriteEndElement();

xmlwriter.WriteElementString("women", "jean"); //<women>jean</women>

xmlwriter.WriteStartElement("children");
xmlwriter.WriteAttributeString("name", "kiddy");
xmlwriter.WriteString("nickey kiddy"); //文本区
xmlwriter.WriteEndElement();

xmlwriter.WriteEndElement();
}
*/
#endregion

#region 使用优化的XPath--XPathDocument类, 速度快, 也支持结构化的查询方式. 缺点: 只能读不能写
//1.创建XPathDocument对象
System.Xml.XPath.XPathDocument xpdoc =new System.Xml.XPath.XPathDocument("XMLOperation.xml");

//2.通过导航器进行查找
System.Xml.XPath.XPathNavigator xpnav = xpdoc.CreateNavigator();

/*#######################################################################################
* 带有命名空间的XML
//定义命名空间管理器
System.Xml.XmlNamespaceManager xnm = new System.Xml.XmlNamespaceManager(xpnav.NameTable);
xnm.AddNamespace("xsi","
http://www.w3.org/2001/XMLSchema-instance");
string nmxpath = "/xsi:configuration/xsi:system.web/xsi:httpHandlers/xsi:add/@type";
System.Xml.XPath.XPathExpression nmxpe = System.Xml.XPath.XPathExpression.Compile(nmxpath);
nmxpe.SetContext(xnm); //在XPath表达式上设置当前的命名空间管理器
System.Xml.XPath.XPathNavigator nmresultNav = xpnav.SelectSingleNode(nmxpe);
Console.WriteLine(nmresultNav.Value);
*#######################################################################################
*/

//3.经过编译的XPath
string xpath ="/configuration/system.web/httpHandlers/cellphone";
System.Xml.XPath.XPathExpression xpe
= System.Xml.XPath.XPathExpression.Compile(xpath);

//4.使用导航器的Select迭代器进行查找, 查找的结果还是导航器
System.Xml.XPath.XPathNavigator resultNav = xpnav.SelectSingleNode(xpe);
Console.WriteLine(
"----------XPathDocument的查询单个结果----------");
Console.WriteLine(resultNav.Value);
//查找多个结果
Console.WriteLine("----------XPathDocument的查询多个结果----------");
xpath
="/configuration/system.web/httpHandlers/add/@type"; //查找add元素的type属性内容
xpe = System.Xml.XPath.XPathExpression.Compile(xpath);
System.Xml.XPath.XPathNodeIterator xpniter
= xpnav.Select(xpe);
foreach (System.Xml.XPath.XPathNavigator xpn in xpniter)
{
Console.WriteLine(xpn.Value);
}

#endregion
}

staticvoid dealSchemaValidation(object sender, System.Xml.Schema.ValidationEventArgs e)
{
Console.WriteLine(
"验证过程出错, 错误等级:{0}, 错误详情:{1}", e.Severity, e.Message);
}
}
}

二、 生成Excel

数据库对于一般的公司职员来说, 似乎不太容易上手. 但他们是对Excel文件, 确是”情有独钟”. 那么, 我们程序员处理完的各项数据最好能够保存为一般职员擅长的Excel文件. 但是, .NET并没有给我们提供创建Excel的方式, 但是我们可以通过xml来生成Excel文件, excel文件也可以另存为xml文件.

下面的例子, 用来演示xml和excel交互处理情况.

//处理带有命名空间的XML文件的元素和属性, ---生成Excel的xml文档; 以及使用ExcelXmlWriter生成Excel文档.

//Program.cs

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

namespace XmlAndExcelDemo
{
class Program
{
//元素的命名空间经常使用, 这里使用串存放命名空间串, 不加冒号表示默认命名空间
privateconststring o ="urn:schemas-microsoft-com:office:office";
privateconststring x ="urn:schemas-microsoft-com:office:excel";
privateconststring ss="urn:schemas-microsoft-com:office:spreadsheet";//ss就是默认命名空间
privateconststring html ="http://www.w3.org/TR/REC-html40";

staticvoid Main(string[] args)
{
#region 处理带有命名空间的XML, --- 生成Excel使用的xml文档
/*
//Dom(Document Object Model)通用性更强, 这里采用Dom树(文件对象模型)方式生成XML文件
//创建Dom对象的实例, 即根结点
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();

//由于XmlVersion那行由系统生成, 因此创建的第一个元素, 即为范本中的第二行
//创建指令对象, xml version标记会自动生成, 不需要书写
//System.Xml.XmlProcessingInstruction xmlpi = new System.Xml.XmlProcessingInstruction();//---X, 指令须通过XmlDocument对象创建(Create方法)
System.Xml.XmlProcessingInstruction xmlpi = doc.CreateProcessingInstruction("mso-application", "progid='Excel.Sheet'");
doc.AppendChild(xmlpi);

//创建根元素Workbook(第一个Element元素, 这里指的不是根, 根是document)
System.Xml.XmlElement workbook = doc.CreateElement("Workbook",ss);//dom树中, 元素的创建都通过document进行, 因为各元素的命名空间经常使用, 可以作为串放在外边
workbook.SetAttribute("xmlns:o",o);
workbook.SetAttribute("xmlns:x",x);
workbook.SetAttribute("xmlns:ss",ss);
workbook.SetAttribute("xmlns:html",html);
doc.AppendChild(workbook);


//创建Styles元素-----<Styles块>
System.Xml.XmlElement styles = doc.CreateElement("Styles",ss);
workbook.AppendChild(styles);

//创建style元素
System.Xml.XmlElement style = doc.CreateElement("Style",ss);
style.SetAttribute("ID",ss,"Default");
style.SetAttribute("Name",ss,"Normal");
styles.AppendChild(style);

//创建Alignment元素
System.Xml.XmlElement alignment = doc.CreateElement("Alignment",ss);
alignment.SetAttribute("Vertical",ss,"Center");
style.AppendChild(alignment);

//创建Font元素
System.Xml.XmlElement font = doc.CreateElement("Font",ss);
font.SetAttribute("FontName",ss,"宋体");
font.SetAttribute("CharSet",x,"134");
font.SetAttribute("Size",ss,"12");
style.AppendChild(font);


//创建WorkSheet-----<WorkSheet块>
System.Xml.XmlElement worksheet = doc.CreateElement("Worksheet",ss);
worksheet.SetAttribute("Name",ss,"Sheet1");
workbook.AppendChild(worksheet);

//创建table元素
System.Xml.XmlElement table = doc.CreateElement("Table",ss);
table.SetAttribute("ExpandedColumnCount", ss, "1");
table.SetAttribute("ExpandedRowCount", ss, "5");
table.SetAttribute("FullColumns", x, "1");
table.SetAttribute("FullRows",x,"1");
table.SetAttribute("DefaultColumnWidth", ss, "54");
table.SetAttribute("DefaultRowHeight", ss, "14.25");
worksheet.AppendChild(table);

//创建Row元素, 通过for循环添加row元素
for (int i = 0; i < 5; i++)
{
System.Xml.XmlElement row = doc.CreateElement("Row", ss);
table.AppendChild(row);
//创建cell元素
System.Xml.XmlElement cell = doc.CreateElement("Cell", ss);
row.AppendChild(cell);
//创建Data元素
System.Xml.XmlElement data = doc.CreateElement("Data", ss);
data.SetAttribute("Type", ss, "Number");
cell.AppendChild(data);
System.Xml.XmlText text = doc.CreateTextNode((i + 1).ToString());
data.AppendChild(text);
}

doc.Save(Console.Out);
Console.WriteLine("\n-----------------------------------------------\n");

//doc.Save("ExcelDemo.xls");//写入XML文件, 但无法还原为Excel, 少一行xml version指令, 需使用字符流
System.IO.TextWriter writer = new System.IO.StreamWriter("ExcelDemo.xls",false,Encoding.UTF8);
doc.Save(writer);
*
*/
#endregion

#region 使用ExcelXmlWriter创建Excel使用的xml, 记得添加ExcelXmlWriter.dll
string filename =@"testAll.xls";
CarlosAg.ExcelXmlWriter.Workbook book
=new CarlosAg.ExcelXmlWriter.Workbook();

// Specify which Sheet should be opened and the size of window by default
//book.ExcelWorkbook, 文档更新不及时的错误
book.ExcelWorkbook.ActiveSheetIndex =1;
book.ExcelWorkbook.WindowTopX
=100;
book.ExcelWorkbook.WindowTopY
=200;
book.ExcelWorkbook.WindowHeight
=7000;
book.ExcelWorkbook.WindowWidth
=8000;

// Some optional properties of the Document
book.Properties.Author ="CarlosAg";
book.Properties.Title
="My Document";
book.Properties.Created
= DateTime.Now;

// Add some styles to the Workbook
CarlosAg.ExcelXmlWriter.WorksheetStyle style = book.Styles.Add("HeaderStyle");
style.Font.FontName
="Tahoma";
style.Font.Size
=14;
style.Font.Bold
=true;
style.Alignment.Horizontal
= CarlosAg.ExcelXmlWriter.StyleHorizontalAlignment.Center;
style.Font.Color
="White";
style.Interior.Color
="Blue";
style.Interior.Pattern
= CarlosAg.ExcelXmlWriter.StyleInteriorPattern.DiagCross;

// Create the Default Style to use for everyone
style = book.Styles.Add("Default");
style.Font.FontName
="Tahoma";
style.Font.Size
=10;

// Add a Worksheet with some data
CarlosAg.ExcelXmlWriter.Worksheet sheet = book.Worksheets.Add("Some Data");

// we can optionally set some column settings
sheet.Table.Columns.Add(new CarlosAg.ExcelXmlWriter.WorksheetColumn(150));
sheet.Table.Columns.Add(
new CarlosAg.ExcelXmlWriter.WorksheetColumn(100));

CarlosAg.ExcelXmlWriter.WorksheetRow row
= sheet.Table.Rows.Add();
row.Cells.Add(
new CarlosAg.ExcelXmlWriter.WorksheetCell("Header 1", "HeaderStyle"));
row.Cells.Add(
new CarlosAg.ExcelXmlWriter.WorksheetCell("Header 2", "HeaderStyle"));
CarlosAg.ExcelXmlWriter.WorksheetCell cell
= row.Cells.Add("Header 3");
cell.MergeAcross
=1; // Merge two cells together
cell.StyleID ="HeaderStyle";

row
= sheet.Table.Rows.Add();
// Skip one row, and add some text
row.Index =3;
row.Cells.Add(
"Data");
row.Cells.Add(
"Data 1");
row.Cells.Add(
"Data 2");
row.Cells.Add(
"Data 3");

// Generate 30 rows
for (int i =0; i <30; i++)
{
row
= sheet.Table.Rows.Add();
row.Cells.Add(
"Row "+ i.ToString());
row.Cells.Add(
new CarlosAg.ExcelXmlWriter.WorksheetCell(i.ToString(), CarlosAg.ExcelXmlWriter.DataType.Number));
}

// Add a Hyperlink
row = sheet.Table.Rows.Add();
cell
= row.Cells.Add();
cell.Data.Text
="Carlos Aguilar Mares";
cell.HRef
="http://www.carlosag.net";
// Add a Formula for the above 30 rows
cell = row.Cells.Add();
cell.Formula
="=SUM(R[-30]C:R[-1]C)";

// Save the file and open it
book.Save(filename);
System.Diagnostics.Process.Start(filename);
#endregion

#region 调用Xslt转换实例
/*
//定义转换对象
System.Xml.Xsl.XslCompiledTransform transform = new System.Xml.Xsl.XslCompiledTransform();

//编译样式表
transform.Load("..\\..\\xsltfile1.xslt");

//执行转换
transform.Transform("..\\..\\xsltfile1.xml", "result.html");
*/
#endregion
}
}
}

/*Exel范本如下:

<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="
http://www.w3.org/TR/REC-html40">
<Styles>
<Style ss:ID="Default" ss:Name="Normal">
<Alignment ss:Vertical="Center"/>
<Font ss:FontName="宋体" x:CharSet="134" ss:Size="12"/>
</Style>
</Styles>
<Worksheet ss:Name="Sheet1">
<Table ss:ExpandedColumnCount="1" ss:ExpandedRowCount="5" x:FullColumns="1"
x:FullRows="1" ss:DefaultColumnWidth="54" ss:DefaultRowHeight="14.25">
<Row>
<Cell><Data ss:Type="Number">1</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="Number">2</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="Number">3</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="Number">4</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="Number">5</Data></Cell>
</Row>
</Table>
</Worksheet>
</Workbook>
*/

三、 关于XML加密和解密的问题

Xml加密(Xml Encryption)是w3c加密xml的标准, 通过加密xml的初始内容被替换, 但其xml格式仍然被保留.

对于xml常见的加密方式有: 对称加密法加密xml、对称加密和非对称加密组合法加密xml(对称加密用来对xml内容加密, 而非对称加密用来对前面的密钥进行加密)、第三方公司提供的X.509加密xml.

常用的是对称加密和非对称加密组合使用, 用来加密xml. 其加密xml的步骤:

加密步骤:

1. 选择XML文档中的一个元素(选择根元素的话将加密整个文档)

2. 使用一个对称加密的密钥加密元素

3. 使用非对象加密来加密2中的密钥(使用公钥加密, 且公钥加密只有私钥可以解密)

4. 创建一个EncryptedData元素, 该元素下将包含被加密的数据和被加密的密钥.

5. 用加密后的元素替换掉初始元素.

解密步骤:

1. 在XML文档中选择一个EncryptedData元素

2. 使用一个非对称密钥来解密密钥(使用私钥解密), 并获得密钥.

3. 使用2中解密后获得的密钥再次对xml内容进行解密.

4. 把EncryptedData元素替换成未加密的元素.

以上这些加密和解密过程的大部分操作, 都可以由.net 2.0中的类自动完成.

这些类涉及System.Xml(包含xml操作类)、System.Security.Cryptography(包含生成加密密钥的类)、System.Security.Cryptography.Xml(包含完成加密任务的类).

关于加密解密的示例:

//Program.cs

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

namespace XmlEncryptAndDecrypt
{
class Program
{
staticvoid Main(string[] args)
{
//模拟PC1上设置Rsa密钥对, 并分发其公钥xml.rsa.public
SetRsaInPC1();

//模拟PC2加密xml, 并发送给PC1
EncryptXMLByPC2();

//模拟PC1上解密XML
DecryptXmlByPC1();
}

privatestaticvoid SetRsaInPC1()
{
//创建非对称密钥对
#region 保存公钥和私钥到文件, 公钥和密钥都类似于XMl中的节点; 处于安全一般不会这样保存
/*
System.Security.Cryptography.RSACryptoServiceProvider rsa = new System.Security.Cryptography.RSACryptoServiceProvider();
string publickey = rsa.ToXmlString(false); //公钥
string privatekey = rsa.ToXmlString(true); //私钥
rsa.Clear();
*
System.IO.StreamWriter sw = new System.IO.StreamWriter("xml.rsa.public",false,Encoding.UTF8);
sw.Write(publickey);
sw.Flush();
sw = new System.IO.StreamWriter("xml.rsa.private", false, Encoding.UTF8);
sw.Write(privatekey);
sw.Close();
*/
#endregion

#region 保存公钥和私钥到本机的密钥容器中. 注意: 密钥对的创建和读取的代码一样
//使用CspParameters对象创建或使用密钥容器
System.Security.Cryptography.CspParameters cp =new System.Security.Cryptography.CspParameters();
cp.KeyContainerName
="Key_Container_XmlRsa"; //设置容器名称
cp.KeyNumber =1; //设置密钥类型为Exchange
cp.Flags = System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore; //设置密钥容器保存位置为计算机密钥库, 默认是用户密钥库
//备注: cp通过Rsa对象的构造函数传递, 且若不存在Key_Container_XmlRsa就创建一个, 若存在就使用它.
#endregion
//公钥和私钥将直接保存到密钥容器中
System.Security.Cryptography.RSACryptoServiceProvider rsa =new System.Security.Cryptography.RSACryptoServiceProvider(cp);

//将公钥存于文件中, 便于向客户机分发
using (System.IO.StreamWriter sw =new System.IO.StreamWriter("xml.rsa.public", false, Encoding.UTF8))
{
sw.Write(rsa.ToXmlString(
false));
sw.Flush();
}
rsa.Clear();
//关闭rsa对象
#region 删除密钥容器
/*删除密钥容器的方法
System.Security.Cryptography.CspParameters cp = new System.Security.Cryptography.CspParameters();
cp.KeyContainerName = "Key_Container_XmlRsa"; //设置容器名称
cp.Flags = System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore;
System.Security.Cryptography.RSACryptoServiceProvider rsa = new System.Security.Cryptography.RSACryptoServiceProvider(cp);
rsa.PersistKeyInCsp = false; //关闭持久密钥
rsa.Clear();
*/
#endregion
}

privatestaticvoid EncryptXMLByPC2()
{
//获得PC1的公钥信息, 并把它必成CryptographyServicesProvider对象(也就是用于加密的rsa)
System.Security.Cryptography.RSACryptoServiceProvider rsa =new System.Security.Cryptography.RSACryptoServiceProvider();
//载入公钥, 公钥也是XML节点
System.Xml.XmlDocument pubkey =new System.Xml.XmlDocument();
pubkey.Load(
"xml.rsa.public");
//将公钥编程csp对象
rsa.FromXmlString(pubkey.OuterXml);

//加载XML文件, 修改时使用XPath方便
System.Xml.XmlDocument xmldoc =new System.Xml.XmlDocument();
System.Xml.XmlDocument encxmldoc
=new System.Xml.XmlDocument(); //加密后xml
xmldoc.Load("XMLOperation.xml");
string xpath ="/configuration/system.web/httpHandlers";
//System.Xml.XmlNodeList nodes = xmldoc.SelectNodes(xpath);
System.Xml.XmlElement encelem; //需要指定加密的XML的元素, 如果没有指定则加密整个xml
if (xpath ==string.Empty)
{
encelem
= xmldoc.DocumentElement; //xmldoc的根元素
}
else
{
encelem
= xmldoc.SelectSingleNode(xpath) as System.Xml.XmlElement;
}

//使用System.Security.Cryptography.Xml.EncryptedXml类完成数据加密和密码加密, 别忘了添加System.Security.dll程序集
System.Security.Cryptography.Xml.EncryptedXml encxml =new System.Security.Cryptography.Xml.EncryptedXml(encxmldoc);
encxml.AddKeyNameMapping(
"cait", rsa); //将密码用rsa加密, 这里的密码cait其实就是个名字, 这里为简单, 直接硬编码密码进去
//加密后的数据
System.Security.Cryptography.Xml.EncryptedData encdata = encxml.Encrypt(encelem, "cait");
//用加密后的数据替换初始元素
System.Security.Cryptography.Xml.EncryptedXml.ReplaceElement(encelem, encdata, false);

Console.WriteLine(
"----------------------加密后的XMl如下------------------------------");
xmldoc.Save(Console.Out);
using (System.IO.StreamWriter sw =new System.IO.StreamWriter("encxmldoc.xml", false, Encoding.UTF8))
{
xmldoc.Save(sw);
}
}

privatestaticvoid DecryptXmlByPC1()
{
//使用CspParameters对象从密钥容器中读取密钥
System.Security.Cryptography.CspParameters cp =new System.Security.Cryptography.CspParameters();
cp.KeyContainerName
="Key_Container_XmlRsa"; //设置容器名称
cp.Flags = System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore; //设置密钥容器保存位置为计算机密钥库, 默认是用户密钥库
System.Security.Cryptography.RSACryptoServiceProvider rsa =new System.Security.Cryptography.RSACryptoServiceProvider(cp);

//载入已加密的xml
System.Xml.XmlDocument encxmldoc =new System.Xml.XmlDocument();
encxmldoc.Load(
"encxmldoc.xml");
System.Security.Cryptography.Xml.EncryptedXml encxml
=new System.Security.Cryptography.Xml.EncryptedXml(encxmldoc);
encxml.AddKeyNameMapping(
"cait", rsa);
//解密所有EncryptedData元素
encxml.DecryptDocument();

//显示解密后结果
encxmldoc.Save(Console.Out);
using (System.IO.StreamWriter sw =new System.IO.StreamWriter("dencxmldoc.xml", false, Encoding.UTF8))
{
encxmldoc.Save(sw);
}
}
}
}

最后, 关于.net2.0下加密和解密web.config文件中的某个section

aspnet_regiis –pef appSettings c:\Inetpu\wwwroot\website

aspnet_regiis –pdf appSettings c:\Inetpu\wwwroot\website

注意: 如果目录名称中有空格, 需要使用引号(双引号或单引号)将路径包围起来.

posted on 2011-02-08 18:22  RJ  阅读(4853)  评论(0编辑  收藏  举报

导航