【问】xml的标准形式是:
<Root>
<Name>John</Name>
<Age>16</Age>
</Root>
现在假如是一个字符串的形式——
<Root><Name>John</Name><Age>16</Age></Root>
请教如何对该字符串格式化,以便成为标准的xml文件格式?
【错误回答】
直接使用XmlDocument的LoadXml方法,然后输出保存到一个新的xml文档中。
【正解】
XmlDocument是存储以及对xml文件操作的一个.NET基本类型。除了对xml进行增删改查之外还可以直接对xml文件进行格式化操作。XmlDocument其中自带一个方法“WriteTo”,该方法需要一个继承TextWriter类的子类。针对xml文件,应该选用XmlTextWriter;XmlTextWriter又需要一个StringWriter流,而StringWriter需要一个Stream对象。恰巧StringBuilder是实现了Stream抽象类的子类。因此可以被使用。代码如下:
[C#]
XmlDocument doc = new XmlDocument();
doc.LoadXml("<Root><Name>John</Name><Age>16</Age></Root>");
StringBuilder sub = new StringBuilder();
StringWriter sw = new StringWriter(sub);
XmlTextWriter xw = new XmlTextWriter(sw);
xw.Formatting = Formatting.Indented;
doc.WriteTo(xw);
Console.WriteLine(sub);
[VB.NET]
Dim doc As New XmlDocument()
doc.LoadXml("<Root><Name>John</Name><Age>16</Age></Root>")
Dim [sub] As New StringBuilder()
Dim sw As New StringWriter([sub])
Dim xw As New XmlTextWriter(sw)
xw.Formatting = Formatting.Indented
doc.WriteTo(xw)
Console.WriteLine([sub])
值得注意的是:您必须设置XmlTextWriter的Formatting格式为Indented(锯齿,自动缩进的意思),否则仍然无法实现效果。
【总结】
1) 首先声明一个StringBuilder对象,作为目标源。
2) 其次声明一个StringWriter,作为连接该对象的“管道”(字符串“写入流”)。
3)然后声明一个XmlTextWriter,连接StringWriter(把StringWriter作为参数传入),并设置Formatting格式为Indented。
4)最后通过XmlDocument的WriteTo方法连接到XmlTextWriter即可。
【拓展】
关于“Stream”,“Reader/Writer”的“IO”探讨
众所周知,System.IO命名空间里边包括了大量支持文件、内存、网络、字符串等流写入(出)的类以及旗下方法。其主要从几个抽象类派生而成:
1)Stream:该类主要用作目标对象。一般地,微软这方面命名是:“目标对象”+Stream——
文件流:FileStream。
内存流:MemoryStream。
网络流:NetWorkStream(值得注意的是有一个类是位于System.NET.Sockets,专门用Socket或者TCP/IP等通讯发送信息时用)。
2) TextWriter:该类用于执行“写”操作,写入到指定某个继承Stream类的子类。这方面微软有对应的类:
文件、内存、网络流写入:StreamWriter。
字符串流写入:StringWriter(注意:其需要一个StringBuilder,而不是需要一个Stream子类对象作为参数)。
Xml文件流写入:XmlWriter和XmlTextWriter,前者自身是一个抽象类(不是继承TextWriter),单独也可以使用(使用Create方法,支持Stream和StringBuilder等),简单实现一些非常简单基本的xml读写操作(主要针对字符串格式的),后者继承了XmlWriter(构造函数参数支持对Stream和TextWriter子类进行写入),实现了其中所有的abstract方法,能够读写复杂的数据类型,如CData等)。同时还支持Formatting格式化,就像上面的例子。
不过有意思的在于:凡是以上类(以Writer结尾的),要写入到目标中的话必须显式调用Close或者Flush方法,否则这是驻留在内存中,不会真正写入到目标的。这也就是为什么很多时候程序没有错误,目标总是得不到的原因。
3) TextReader:该类用于执行“读”操作,读入到指定某个继承Stream类的子类。这方面微软有对应的类:
文件、内存、网络流读入:StreamReader。
字符串流读入:StringReader(注意:其需要一个string对象,而不是需要一个Stream子类对象作为参数)。
Xml文件流读入:XmlReader和XmlTextReader,前者自身是一个抽象类(不是继承TextReader),单独也可以使用(使用Create方法,支持TextReader和Stream等),简单实现一些非常简单基本的xml读写操作(主要针对字符串格式的),后者继承了XmlWriter,实现了其中所有的abstract方法,能够读写复杂的数据类型等)。