《软件测试自动化之道》读书笔记 之 XML测试
2014-10-07
待测程序
测试程序
通过XmlTextReader解析XML
通过XmlDocument解析XML
通过XmlPathDocument解析XML
通过XmlSerializer解析XML
通过DataSet解析XML
通过XSD Schema对XML文件进行验证
通过XSLT对XML文件进行修改
通过XmlTextWrite对XML文件进行写操作
比较两个XML文件是否严格相等
不考虑编码方式,比较两个XML文件是否严格相等
比较两个XML文件的规范等价性
示例代码
待测程序
返回
‘testCases.xml’示例代码:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <suite> 3 <testcase id="001" bvt="yes"> 4 <inputs> 5 <arg1>red</arg1> 6 <arg2>blue</arg2> 7 </inputs> 8 <expected>purple</expected> 9 </testcase> 10 11 <testcase id="002" bvt="no"> 12 <inputs> 13 <arg1>blue</arg1> 14 <arg2>yellow</arg2> 15 </inputs> 16 <expected>green</expected> 17 </testcase> 18 19 <testcase id="003" bvt="yes"> 20 <inputs> 21 <arg1>white</arg1> 22 <arg2>black</arg2> 23 </inputs> 24 <expected>gray</expected> 25 </testcase> 26 </suite>
测试程序
返回
本章给出5种解析技术,都是把‘testCases.xml’解析成测试用例Suite对象,Suite的定义如下:
1 namespace Utility 2 { 3 public class TestCase 4 { 5 public string id; 6 public string bvt; 7 public string arg1; 8 public string arg2; 9 public string expected; 10 } 11 12 public class Suite 13 { 14 public System.Collections.ArrayList cases = new System.Collections.ArrayList(); 15 public void Display() 16 { 17 foreach (TestCase tc in cases) 18 { 19 Console.WriteLine(tc.id + " " + tc.bvt + " " + tc.arg1 + " " + tc.arg2 + " " + tc.expected); 20 } 21 } 22 } 23 }
通过XmlTextReader解析XML
示例代码:
1 private static void ParseByXMLTextReader(Utility.Suite suite, string tcPath) 2 { 3 XmlTextReader xtr = new XmlTextReader(tcPath); 4 xtr.WhitespaceHandling = WhitespaceHandling.None; 5 xtr.Read(); //read xml declaration, move to tag<suite> 6 7 while (!xtr.EOF) 8 { 9 if (xtr.Name == "suite" && !xtr.IsStartElement()) break; 10 while (xtr.Name != "testcase" || !xtr.IsStartElement()) 11 xtr.Read(); //move to tag<testcase> 12 13 Utility.TestCase tc = new Utility.TestCase(); 14 tc.id = xtr.GetAttribute("id"); 15 tc.bvt = xtr.GetAttribute("bvt"); 16 xtr.Read(); //move to tag <inputs> 17 xtr.Read(); //move to tag <arg1> 18 tc.arg1 = xtr.ReadElementString("arg1"); 19 tc.arg2 = xtr.ReadElementString("arg2"); 20 xtr.Read(); //move to tag <expected> 21 tc.expected = xtr.ReadElementString("expected"); 22 //current tag is </testcase> 23 suite.cases.Add(tc); 24 25 xtr.Read(); //current tag is <testcase> or </suite> 26 } 27 xtr.Close(); 28 } 29 }
分析:
XmlTextReader把XML 解析成单个的数据片,如下xml:
<?xml version="1.0" encoding="utf-8" ?> <alpha id="001"> <beta>123</beta> </alpha>
不计空格,这里共有6个结点:XML声明、<alpha id="001">、<beta>、123、</beta>、</alpha>。
- Read()方法:每次向前读取一个结点。与其它类的Read()不同,该方法并不返回有意义的数据;
- ReadElementString()方法:才会返回单个标签和结尾之间的数据,并向前糯稻标签结束后面的下一个结点。
- EOF属性:判断是否碰到文件结尾
当被解析的XML文件结构相对比较简单并且前后一致,且需要向前进行处理的时候,使用XmlTextReader是 一种直接有效的方法。与本章其他解析技术相比,也是最快的方法。与本章其他解析技术相比,XmlTextReader所进行的操作在比较地的抽象层次上,也就以为这作为程序员,要负责正确跟踪XML文件中的位置和正确调用Read()。
通过XmlDocument解析XML
示例代码:
1 private static void ParseByXMLDocument(Utility.Suite suite, string tcPath) 2 { 3 XmlDocument xd = new XmlDocument(); 4 xd.Load(tcPath); 5 6 //get all <testcase> nodes 7 XmlNodeList nodeList = xd.SelectNodes("/suite/testcase"); 8 foreach (XmlNode node in nodeList) 9 { 10 Utility.TestCase tc = new Utility.TestCase(); 11 tc.id = node.Attributes.GetNamedItem("id").Value; 12 tc.bvt = node.Attributes.GetNamedItem("bvt").Value; 13 14 XmlNode n = node.SelectSingleNode("inputs"); 15 tc.arg1 = n.ChildNodes.Item(0).InnerText; 16 tc.arg2 = n.ChildNodes.Item(1).InnerText; 17 tc.expected = node.ChildNodes.Item(1).InnerText; 18 19 suite.cases.Add(tc); 20 } 21 }
分析:
XmlDocument.Load()方法:把整个XML文件读如内存中。XmlDocument对象基于XML结点和子结点的概念。我们不采用顺序的方式遍历XML文件,而是通过SelectNodes()方法选择一组结点,或这通过SelectSingleNode()选择单个的结点。请注意:因为XML文件的attributes和elements之间有着显著的差别,所以我们必须通过Attributes.GetNamedItem()方法得到某个元素结点的id和bvt值。
因为XmlDocument会一次把整个XML文挡读入到内存中,所以对于被解析的XML文件非常大的情况,这种方法并不合适。
通过XmlPathDocument解析XML
示例代码:
1 private static void ParseByXPathDocument(Utility.Suite suite, string tcPath) 2 { 3 System.Xml.XPath.XPathDocument xpd = new XPathDocument(tcPath); 4 XPathNavigator xpn = xpd.CreateNavigator(); 5 XPathNodeIterator xpi = xpn.Select("/suite/testcase"); 6 7 while (xpi.MoveNext()) 8 { 9 Utility.TestCase tc = new Utility.TestCase(); 10 tc.id = xpi.Current.GetAttribute("id", xpn.NamespaceURI); 11 tc.bvt = xpi.Current.GetAttribute("bvt", xpn.NamespaceURI); 12 13 XPathNodeIterator tcChild = xpi.Current.SelectChildren(XPathNodeType.Element); 14 while (tcChild.MoveNext()) 15 { 16 17 if (tcChild.Current.Name == "inputs") 18 { 19 XPathNodeIterator tcSubChild = tcChild.Current.SelectChildren(XPathNodeType.Element); 20 while (tcSubChild.MoveNext()) 21 { 22 if (tcSubChild.Current.Name == "arg1") 23 tc.arg1 = tcSubChild.Current.Value; 24 else if (tcSubChild.Current.Name == "arg2") 25 tc.arg2 = tcSubChild.Current.Value; 26 } 27 } 28 else if (tcChild.Current.Name == "expected") 29 tc.expected = tcChild.Current.Value; 30 31 } 32 suite.cases.Add(tc); 33 } 34 }
分析:
- XpathDocument()构造函数:把整个XML文件存入内存。
- XpathNavigator对象的Select()方法:选择XML文挡的一部分
- XpathNodeIterator对象的MoveNext()方法:遍历XpathDocument对象。
- GetAttribut()方法:取得attribute的值
- SelectChildren()方法和Current.Value属性:取得XML元素的值
通过XmlPathDocument对象对XML文件进行解析,给人的感觉是它一部分是过程式的、底层的(类似于XmlTextReader)处理方法,一部分是面向对象的、高层次的(类似于XMLDocument)的处理方法。
XmlPathDocument类是针对XPath数据模型特别优化过的。所以当要解析的XML文件嵌套层次很深、结构很复杂或者需要大范围的查找炒作,这种方法尤为合适。但XmlPathDocument只能对XML文件进行读取,所以如果想对文件在内存中进行直接的操作,这种方法不行。
通过XmlSerializer解析XML
示例代码:
内存结构对应类:
1 namespace SerializerLib 2 { 3 using System.Xml.Serialization; 4 5 [XmlRootAttribute("suite")] 6 public class Suite 7 { 8 [XmlElementAttribute("testcase")] 9 public TestCase[] items; 10 public void Display() 11 { 12 foreach(TestCase tc in items) 13 { 14 Console.WriteLine(tc.id + " " + tc.bvt + " " + tc.inputs.arg1 + " " + tc.inputs.arg2 + " " + tc.expected); 15 } 16 } 17 18 } 19 20 public class TestCase 21 { 22 [XmlAttributeAttribute()] 23 public string id; 24 [XmlAttributeAttribute()] 25 public string bvt; 26 [XmlElementAttribute("inputs")] 27 public Inputs inputs; 28 public string expected; 29 30 } 31 32 public class Inputs 33 { 34 public string arg1; 35 public string arg2; 36 } 37 }
ParseByXmlSerializer()方法:
1 private static void ParseByXmlSerializer(string tcPath) 2 { 3 XmlSerializer xs = new XmlSerializer(typeof(SerializerLib.Suite)); 4 StreamReader sr = new StreamReader(tcPath); 5 SerializerLib.Suite suite = (SerializerLib.Suite)xs.Deserialize(sr); 6 sr.Close(); 7 suite.Display(); 8 }
分析:
通过XmlSerializer类对XML文件进行解析于其他5中XML解析类有着很大的不同,因为采用这种方法必须很仔细的把存储结构预先准备好。我们注意到把XML加载到内存中的操作只通过下面一个语句就完成了:
SerializerLib.Suite suite = (SerializerLib.Suite)xs.Deserialize(sr);
存储结构可以手工编写一个目标类,也可以通过Visual Studio .NET自带的xsd.exe命令行工具:
首先,执行以下命令(假设testCase.xml位于C盘根目录):
C:\>xsd.exe testCases.xml /o:.
这个命令的意思上创建testCases.xml文件的XSD schema定义并且把结果按照默认名保存到当前目录
然后,执行以下命令:
C:\xsd.exe testCases.xsd /c /o:.
这个命令的意思是使用testCase.xsd定义文件,通过默认的C#语言产生一组于Deserialize()方法兼容的类,并且以默认文件名testCases.cs保存到当前目录。
现在你可以把testCases.cs的代码直接拷贝到测试套间中,稍加修改(比如:去处一些不需要的代码,加一些额外的方法,改名等)
XmlSerialzier类为XML文件的解析提供了一种非常优雅的解决方案。所进行的操作也在最高的抽象层次,也就是说算法的细节大多屏蔽掉了。但也失去了一些对XML处理过程的处理。
通过DataSet解析XML
示例代码:
1 private static void ParseByDataSet(Utility.Suite suite, string tcPath) 2 { 3 DataSet ds = new DataSet(); 4 ds.ReadXml(tcPath); 5 6 foreach (DataRow row in ds.Tables["testcase"].Rows) 7 { 8 Utility.TestCase tc=new Utility.TestCase(); 9 tc.id = row["id"].ToString(); 10 tc.bvt = row["bvt"].ToString(); 11 tc.expected = row["expected"].ToString(); 12 13 DataRow[] children = row.GetChildRows("testcase_inputs"); //relation name 14 tc.arg1=(children[0]["arg1"]).ToString(); 15 tc.arg2=(children[0]["arg2"]).ToString(); 16 17 suite.cases.Add(tc); 18 } 19 }
分析:
ReadXml()方法:把XML文件直接读如一个System.Data.DataSet对象。你可以把DataSet对象想像成一个内存中的关系型数据库。通过DataSet对象对XML进行解析,关键是要理解XML(本质上是层次型的)是如何映射到一组DataTable对象(本质上是平面型的)的。XML源文件的每个层次都会在DataSet中产生一个表。
顶层的<testcase>产生一个名为testcase的DataTable。下一层次<inputs>产生一个名为inputs的DataTable。这时候还会产生一个叫做testcase_inputs的关系对象用来连接DataTable对象。请注意:XML的根结点所在的层次和最低层(本例中即<arg>所表示的数据)并不会产生表。
下面这个‘DisplayInfo’方法的代码提供一些你需要的信息:
1 public static void DisplayInfo(DataSet ds) 2 { 3 foreach (DataTable dt in ds.Tables) 4 { 5 Console.WriteLine("\n=========================================="); 6 Console.WriteLine("Table= " + dt.TableName + "\n"); 7 foreach (DataColumn dc in dt.Columns) 8 Console.Write("{0,-14}", dc.ColumnName); 9 Console.WriteLine("\n------------------------------------------"); 10 foreach (DataRow dr in dt.Rows) 11 { 12 foreach(object data in dr.ItemArray) 13 Console.Write("{0,-14}", data.ToString()); 14 Console.WriteLine(); 15 } 16 Console.WriteLine("\n=========================================="); 17 } 18 foreach (DataRelation dr in ds.Relations) 19 { 20 Console.WriteLine("\n\nRelations:"); 21 Console.WriteLine(dr.RelationName+"\n\n"); 22 } 23 }
图1 DataSet信息
通过XSD Schema对XML文件进行验证
示例代码:
1 private static void VerifyByXsdSchema(string tcPath) 2 { 3 XmlSchemaCollection xsc = new XmlSchemaCollection(); 4 xsc.Add(null, @"..\..\testCases.xsd"); 5 XmlTextReader xtr = new XmlTextReader(tcPath); 6 XmlValidatingReader xvr = new XmlValidatingReader(xtr); 7 xvr.ValidationType = ValidationType.Schema; 8 xvr.Schemas.Add(xsc); 9 xvr.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack); 10 while (xvr.Read()) ; 11 12 Console.WriteLine("If no error message then XML is valid"); 13 }
分析:
通过XmlValidatingReader对象对想要验证的XML文件进行遍历。如果这个文件不是有效的XML文件,程序控制流程转向一个代理方法(delegate method),这个代理方法会打印出错误信息。
通过XmlSchemaCollection对象加载用于验证的schema定义,通过这种方法可以针对XML文件应用多个schema定义。
通过XSLT对XML文件进行修改
‘testCase.xml’原始形式如下:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <suite> 3 <testcase id="001" bvt="yes"> 4 <inputs> 5 <arg1>red</arg1> 6 <arg2>blue</arg2> 7 </inputs> 8 <expected>purple</expected> 9 </testcase> 10 11 <suite>
修改后的版本:
1 <?xml version="1.0" encoding="utf-8"?> 2 <allOfTheTestCases> 3 <aCase caseID="001"> 4 <bvt>yes</bvt> 5 <expRes>purple</expRes> 6 <inputs> 7 <input1>red</input1> 8 <input2>blue</input2> 9 </inputs> 10 </aCase> 11 12 </allOfTheTestCases>
示例代码:
‘testCasesModifier.xslt’代码:
1 <?xml version="1.0" encoding="utf-8"?> 2 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 3 xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" 4 > 5 <xsl:output method="xml" indent="yes"/> 6 7 <xsl:template match="/"> 8 <allOfTheTestCases> 9 <xsl:for-each select ="//testcase"> 10 <aCase> 11 <xsl:attribute name="caseID"> 12 <xsl:value-of select ="@id"/> 13 </xsl:attribute> 14 <bvt> 15 <xsl:value-of select="@bvt"/> 16 </bvt> 17 <expRes> 18 <xsl:value-of select="expected"/> 19 </expRes> 20 <inputs> 21 <xsl:for-each select="inputs"> 22 <input1> 23 <xsl:value-of select="arg1"/> 24 </input1> 25 <input2> 26 <xsl:value-of select="arg2"/> 27 </input2> 28 </xsl:for-each> 29 </inputs> 30 </aCase> 31 </xsl:for-each> 32 </allOfTheTestCases> 33 </xsl:template> 34 </xsl:stylesheet>
UpdateXMLByXSLT()方法代码:
1 private static void UpdateXMLByXSLT(string tcPath) 2 { 3 XslTransform xst = new XslTransform(); 4 xst.Load(@"..\..\testCasesModifier.xslt"); 5 xst.Transform(tcPath, @"..\..\testCasesModifier.xml"); 6 Console.WriteLine("Done. New XML file is ‘testCasesModifier.xml‘"); 7 }
通过XmlTextWrite对XML文件进行写操作
示例代码:
1 private static void WriteXMLbyXmlTextWrite() 2 { 3 string caseID = "0001"; 4 string result = "Pass"; 5 string whenRun = "10/09/2014"; 6 XmlTextWriter xtw = new XmlTextWriter(@"..\..\Results1.xml", System.Text.Encoding.UTF8); 7 xtw.Formatting = Formatting.Indented; 8 xtw.WriteStartDocument(); 9 xtw.WriteStartElement("Results"); 10 xtw.WriteStartElement("result"); 11 xtw.WriteAttributeString("id", caseID); 12 xtw.WriteStartElement("passfaill"); 13 xtw.WriteString(result); 14 xtw.WriteEndElement(); 15 xtw.WriteStartElement("whenRun"); 16 xtw.WriteString(whenRun); 17 xtw.WriteEndElement(); 18 xtw.WriteEndElement(); 19 xtw.WriteEndElement(); 20 xtw.Close(); 21 }
结果‘TestResult1.xml’:
1 <?xml version="1.0" encoding="utf-8"?> 2 <Results> 3 <result id="0001"> 4 <passfaill>Pass</passfaill> 5 <whenRun>10/09/2014</whenRun> 6 </result> 7 </Results>
比较两个XML文件是否严格相等
示例代码:
1 private static bool XMLExactlySame(string file1,string file2) 2 { 3 FileStream fs1 = new FileStream(file1, FileMode.Open); 4 FileStream fs2 = new FileStream(file2, FileMode.Open); 5 6 if (fs1.Length != fs2.Length) 7 return false; 8 else 9 { 10 int b1 = 0; 11 int b2 = 0; 12 13 while ((b1 = fs1.ReadByte()) != -1) 14 { 15 b2 = fs2.ReadByte(); 16 if (b1 != b2) 17 { 18 fs1.Close(); 19 fs2.Close(); 20 return false; 21 } 22 } 23 fs1.Close(); 24 fs2.Close(); 25 return true; 26 } 27 }
分析:
通过FileStream对象遍历两个XML文件。一个字节一个字节的读入文件内容,如果某个字节不匹配,则返回false。
不考虑编码方式,比较两个XML文件是否严格相等
示例代码:
1 private static bool XMLExactlyExceptEncoding(string file1, string file2) 2 { 3 FileStream fs1 = new FileStream(file1, FileMode.Open); 4 FileStream fs2 = new FileStream(file2, FileMode.Open); 5 StreamReader sr1 = new StreamReader(fs1); 6 StreamReader sr2 = new StreamReader(fs2); 7 8 string s1 = sr1.ReadToEnd(); 9 string s2 = sr2.ReadToEnd(); 10 sr1.Close(); 11 sr2.Close(); 12 fs1.Close(); 13 fs2.Close(); 14 return (s1==s2); 15 }
分析:
编写软件测试时,可能需要对实际的XML文件和期望的XML文件进行比较,而不关心它们的编码机制是否一样。换句话说,如果实际的XML文件和期望的XML文件包含相同的字符数据,只不过编码方式不同(比如:UTF-8,ANSI )。若要考虑编码,可用重载过的==运算符。
比较两个XML文件的规范等价性
第一个XML文件Books1.xml代码如下:
1 <?xml version="1.0" encoding="utf-8"?> 2 <books> 3 4 <book> 5 <title isbn=‘1111‘ storeid="A1A1"> 6 All About Apples 7 </title> 8 <author> 9 <last>Anderson</last> 10 <first>Adam</first> 11 </author> 12 </book> 13 </books>
第二个XML文件Books2.xml代码如下:
1 <books> 2 <book> 3 <title storeid="A1A1" isbn="1111"> 4 All About Apples 5 </title> 6 <author> 7 <last>Anderson</last> 8 <first>Adam</first> 9 </author> 10 </book> 11 </books>
示例代码:
1 private static void XMLCanonicalEquivalence() 2 { 3 string file1 = @"..\..\Books1.xml"; 4 string file2 = @"..\..\Books2.xml"; 5 6 XmlDocument xd1 = new XmlDocument(); 7 xd1.Load(file1); 8 9 XmlDsigC14NTransform t1 = new XmlDsigC14NTransform(true); //true mean inclue comment 10 11 t1.LoadInput(xd1); 12 Stream s1 = t1.GetOutput() as Stream; 13 XmlTextReader xtr1 = new XmlTextReader(s1); 14 MemoryStream ms1 = new MemoryStream(); 15 XmlTextWriter xtw1 = new XmlTextWriter(ms1, System.Text.Encoding.UTF8); 16 xtw1.WriteNode(xtr1, false); //false mean not copy default properties 17 18 xtw1.Flush(); 19 ms1.Position = 0; 20 StreamReader sr1 = new StreamReader(ms1); 21 string str1 = sr1.ReadToEnd(); 22 Console.WriteLine(str1); 23 24 Console.WriteLine("\n==============\n"); 25 26 XmlDocument xd2 = new XmlDocument(); 27 xd2.Load(file2); 28 29 XmlDsigC14NTransform t2 = new XmlDsigC14NTransform(true); //true mean inclue comment 30 31 t2.LoadInput(xd2); 32 Stream s2 = t2.GetOutput() as Stream; 33 XmlTextReader xtr2 = new XmlTextReader(s2); 34 MemoryStream ms2 = new MemoryStream(); 35 XmlTextWriter xtw2 = new XmlTextWriter(ms2, System.Text.Encoding.UTF8); 36 xtw2.WriteNode(xtr2, false); //false mean not copy default properties 37 38 xtw2.Flush(); 39 ms2.Position = 0; 40 StreamReader sr2 = new StreamReader(ms2); 41 string str2 = sr2.ReadToEnd(); 42 Console.WriteLine(str2); 43 44 if (str1 == str2) 45 Console.WriteLine("Files cannonically equivalent"); 46 else 47 Console.WriteLine("Files Not canonically equivalent"); 48 }
分析:
通过XmlDsigC14NTransform类对两个要比较的XML文件实施C14N规范花转换,然后通过两个MemoryStream对象对内存中两个转换后文件进行比较。你可以把规范等价性想像成“从大多数实际应用的角度来看都是相等的”。
上面两个XML文件‘Books1.xml’,‘Bools2.xml’具有规范等价性。两个文件中的空格不影响比较的结果;但引号双引号不影响比较的结果;XML声明不影响比较的结果;attributes的顺序不影响比较的结果。
C14N规范等价性是相当复杂的。它是有W3C定义的,主要用于安全领域,XmlDsigC14NTransform类位于System.Security.dll中。为了判断一个XML文件在网络传输的过程中是否被无意中修改或被恶意修改,我们可以比较发送文件和接受文件加密哈希值。但是,由于网络可能会修改这个文件,我们需要以某种方式来判断它们的规范等价性。
示例代码
1 using System; 2 using System.Text; 3 4 using System.Xml; 5 using System.Xml.XPath; 6 7 using System.Xml.Serialization; 8 using System.IO; 9 using System.Data; 10 using System.Xml.Schema; 11 using System.Xml.Xsl; 12 13 using System.Security.Cryptography.Xml; 14 15 namespace XMLTest 16 { 17 class Program 18 { 19 static void Main(string[] args) 20 { 21 Console.WriteLine("Start\n"); 22 string tcPath = @"..\..\testCases.xml"; 23 //Utility.Suite suite = new Utility.Suite(); 24 25 //ParseByXMLTextReader(suite, tcPath); 26 //ParseByXMLDocument(suite, tcPath); 27 //ParseByXPathDocument(suite, tcPath); 28 //ParseByXmlSerializer(suite, tcPath); 29 //ParseByDataSet(suite, tcPath); 30 31 //suite.Display(); 32 33 //VerifyByXsdSchema(tcPath); 34 //UpdateXMLByXSLT(tcPath); 35 //WriteXMLbyXmlTextWrite(); 36 37 //XMLExactlySame 38 //XMLExactlyExceptEncoding 39 XMLCanonicalEquivalence(); 40 41 Console.WriteLine("\nDone"); 42 Console.Read(); 43 } 44 45 private static void XMLCanonicalEquivalence() 46 { 47 string file1 = @"..\..\Books1.xml"; 48 string file2 = @"..\..\Books2.xml"; 49 50 XmlDocument xd1 = new XmlDocument(); 51 xd1.Load(file1); 52 53 XmlDsigC14NTransform t1 = new XmlDsigC14NTransform(true); //true mean inclue comment 54 55 t1.LoadInput(xd1); 56 Stream s1 = t1.GetOutput() as Stream; 57 XmlTextReader xtr1 = new XmlTextReader(s1); 58 MemoryStream ms1 = new MemoryStream(); 59 XmlTextWriter xtw1 = new XmlTextWriter(ms1, System.Text.Encoding.UTF8); 60 xtw1.WriteNode(xtr1, false); //false mean not copy default properties 61 62 xtw1.Flush(); 63 ms1.Position = 0; 64 StreamReader sr1 = new StreamReader(ms1); 65 string str1 = sr1.ReadToEnd(); 66 Console.WriteLine(str1); 67 68 Console.WriteLine("\n==============\n"); 69 70 XmlDocument xd2 = new XmlDocument(); 71 xd2.Load(file2); 72 73 XmlDsigC14NTransform t2 = new XmlDsigC14NTransform(true); //true mean inclue comment 74 75 t2.LoadInput(xd2); 76 Stream s2 = t2.GetOutput() as Stream; 77 XmlTextReader xtr2 = new XmlTextReader(s2); 78 MemoryStream ms2 = new MemoryStream(); 79 XmlTextWriter xtw2 = new XmlTextWriter(ms2, System.Text.Encoding.UTF8); 80 xtw2.WriteNode(xtr2, false); //false mean not copy default properties 81 82 xtw2.Flush(); 83 ms2.Position = 0; 84 StreamReader sr2 = new StreamReader(ms2); 85 string str2 = sr2.ReadToEnd(); 86 Console.WriteLine(str2); 87 88 if (str1 == str2) 89 Console.WriteLine("Files cannonically equivalent"); 90 else 91 Console.WriteLine("Files Not canonically equivalent"); 92 } 93 94 private static bool XMLExactlyExceptEncoding(string file1, string file2) 95 { 96 FileStream fs1 = new FileStream(file1, FileMode.Open); 97 FileStream fs2 = new FileStream(file2, FileMode.Open); 98 StreamReader sr1 = new StreamReader(fs1); 99 StreamReader sr2 = new StreamReader(fs2); 100 101 string s1 = sr1.ReadToEnd(); 102 string s2 = sr2.ReadToEnd(); 103 sr1.Close(); 104 sr2.Close(); 105 fs1.Close(); 106 fs2.Close(); 107 return (s1==s2); 108 } 109 110 private static bool XMLExactlySame(string file1,string file2) 111 { 112 FileStream fs1 = new FileStream(file1, FileMode.Open); 113 FileStream fs2 = new FileStream(file2, FileMode.Open); 114 115 if (fs1.Length != fs2.Length) 116 return false; 117 else 118 { 119 int b1 = 0; 120 int b2 = 0; 121 122 while ((b1 = fs1.ReadByte()) != -1) 123 { 124 b2 = fs2.ReadByte(); 125 if (b1 != b2) 126 { 127 fs1.Close(); 128 fs2.Close(); 129 return false; 130 } 131 } 132 fs1.Close(); 133 fs2.Close(); 134 return true; 135 } 136 } 137 138 private static void WriteXMLbyXmlTextWrite() 139 { 140 string caseID = "0001"; 141 string result = "Pass"; 142 string whenRun = "10/09/2014"; 143 XmlTextWriter xtw = new XmlTextWriter(@"..\..\Results1.xml", System.Text.Encoding.UTF8); 144 xtw.Formatting = Formatting.Indented; 145 xtw.WriteStartDocument(); 146 xtw.WriteStartElement("Results"); 147 xtw.WriteStartElement("result"); 148 xtw.WriteAttributeString("id", caseID); 149 xtw.WriteStartElement("passfaill"); 150 xtw.WriteString(result); 151 xtw.WriteEndElement(); 152 xtw.WriteStartElement("whenRun"); 153 xtw.WriteString(whenRun); 154 xtw.WriteEndElement(); 155 xtw.WriteEndElement(); 156 xtw.WriteEndElement(); 157 xtw.Close(); 158 } 159 160 private static void UpdateXMLByXSLT(string tcPath) 161 { 162 XslTransform xst = new XslTransform(); 163 xst.Load(@"..\..\testCasesModifier.xslt"); 164 xst.Transform(tcPath, @"..\..\testCasesModifier.xml"); 165 Console.WriteLine("Done. New XML file is ‘testCasesModifier.xml‘"); 166 } 167 168 private static void VerifyByXsdSchema(string tcPath) 169 { 170 XmlSchemaCollection xsc = new XmlSchemaCollection(); 171 xsc.Add(null, @"..\..\testCases.xsd"); 172 XmlTextReader xtr = new XmlTextReader(tcPath); 173 XmlValidatingReader xvr = new XmlValidatingReader(xtr); 174 xvr.ValidationType = ValidationType.Schema; 175 xvr.Schemas.Add(xsc); 176 xvr.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack); 177 while (xvr.Read()) ; 178 179 Console.WriteLine("If no error message then XML is valid"); 180 } 181 182 private static void ValidationCallBack(object sender, ValidationEventArgs ea) 183 { 184 Console.WriteLine("Validation error: " + ea.Message); 185 Console.ReadLine(); 186 } 187 188 public static void DisplayInfo(DataSet ds) 189 { 190 foreach (DataTable dt in ds.Tables) 191 { 192 Console.WriteLine("\n=========================================="); 193 Console.WriteLine("Table= " + dt.TableName + "\n"); 194 foreach (DataColumn dc in dt.Columns) 195 Console.Write("{0,-14}", dc.ColumnName); 196 Console.WriteLine("\n------------------------------------------"); 197 foreach (DataRow dr in dt.Rows) 198 { 199 foreach(object data in dr.ItemArray) 200 Console.Write("{0,-14}", data.ToString()); 201 Console.WriteLine(); 202 } 203 Console.WriteLine("\n=========================================="); 204 } 205 foreach (DataRelation dr in ds.Relations) 206 { 207 Console.WriteLine("\n\nRelations:"); 208 Console.WriteLine(dr.RelationName+"\n\n"); 209 } 210 } 211 212 private static void ParseByDataSet(Utility.Suite suite, string tcPath) 213 { 214 DataSet ds = new DataSet(); 215 ds.ReadXml(tcPath); 216 217 foreach (DataRow row in ds.Tables["testcase"].Rows) 218 { 219 Utility.TestCase tc=new Utility.TestCase(); 220 tc.id = row["id"].ToString(); 221 tc.bvt = row["bvt"].ToString(); 222 tc.expected = row["expected"].ToString(); 223 224 DataRow[] children = row.GetChildRows("testcase_inputs"); //relation name 225 tc.arg1=(children[0]["arg1"]).ToString(); 226 tc.arg2=(children[0]["arg2"]).ToString(); 227 228 suite.cases.Add(tc); 229 } 230 DisplayInfo(ds); 231 } 232 233 private static void ParseByXmlSerializer(string tcPath) 234 { 235 XmlSerializer xs = new XmlSerializer(typeof(SerializerLib.Suite)); 236 StreamReader sr = new StreamReader(tcPath); 237 SerializerLib.Suite suite = (SerializerLib.Suite)xs.Deserialize(sr); 238 sr.Close(); 239 suite.Display(); 240 } 241 242 private static void ParseByXPathDocument(Utility.Suite suite, string tcPath) 243 { 244 System.Xml.XPath.XPathDocument xpd = new XPathDocument(tcPath); 245 XPathNavigator xpn = xpd.CreateNavigator(); 246 XPathNodeIterator xpi = xpn.Select("/suite/testcase"); 247 248 while (xpi.MoveNext()) 249 { 250 Utility.TestCase tc = new Utility.TestCase(); 251 tc.id = xpi.Current.GetAttribute("id", xpn.NamespaceURI); 252 tc.bvt = xpi.Current.GetAttribute("bvt", xpn.NamespaceURI); 253 254 XPathNodeIterator tcChild = xpi.Current.SelectChildren(XPathNodeType.Element); 255 while (tcChild.MoveNext()) 256 { 257 258 if (tcChild.Current.Name == "inputs") 259 { 260 XPathNodeIterator tcSubChild = tcChild.Current.SelectChildren(XPathNodeType.Element); 261 while (tcSubChild.MoveNext()) 262 { 263 if (tcSubChild.Current.Name == "arg1") 264 tc.arg1 = tcSubChild.Current.Value; 265 else if (tcSubChild.Current.Name == "arg2") 266 tc.arg2 = tcSubChild.Current.Value; 267 } 268 } 269 else if (tcChild.Current.Name == "expected") 270 tc.expected = tcChild.Current.Value; 271 272 } 273 suite.cases.Add(tc); 274 } 275 } 276 277 private static void ParseByXMLDocument(Utility.Suite suite, string tcPath) 278 { 279 XmlDocument xd = new XmlDocument(); 280 xd.Load(tcPath); 281 282 //get all <testcase> nodes 283 XmlNodeList nodeList = xd.SelectNodes("/suite/testcase"); 284 foreach (XmlNode node in nodeList) 285 { 286 Utility.TestCase tc = new Utility.TestCase(); 287 tc.id = node.Attributes.GetNamedItem("id").Value; 288 tc.bvt = node.Attributes.GetNamedItem("bvt").Value; 289 290 XmlNode n = node.SelectSingleNode("inputs"); 291 tc.arg1 = n.ChildNodes.Item(0).InnerText; 292 tc.arg2 = n.ChildNodes.Item(1).InnerText; 293 tc.expected = node.ChildNodes.Item(1).InnerText; 294 295 suite.cases.Add(tc); 296 } 297 } 298 299 private static void ParseByXMLTextReader(Utility.Suite suite, string tcPath) 300 { 301 XmlTextReader xtr = new XmlTextReader(tcPath); 302 xtr.WhitespaceHandling = WhitespaceHandling.None; 303 xtr.Read(); //read xml declaration, move to tag<suite> 304 305 while (!xtr.EOF) 306 { 307 if (xtr.Name == "suite" && !xtr.IsStartElement()) break; 308 while (xtr.Name != "testcase" || !xtr.IsStartElement()) 309 xtr.Read(); //move to tag<testcase> 310 311 Utility.TestCase tc = new Utility.TestCase(); 312 tc.id = xtr.GetAttribute("id"); 313 tc.bvt = xtr.GetAttribute("bvt"); 314 xtr.Read(); //move to tag <inputs> 315 xtr.Read(); //move to tag <arg1> 316 tc.arg1 = xtr.ReadElementString("arg1"); 317 tc.arg2 = xtr.ReadElementString("arg2"); 318 xtr.Read(); //move to tag <expected> 319 tc.expected = xtr.ReadElementString("expected"); 320 //current tag is </testcase> 321 suite.cases.Add(tc); 322 323 xtr.Read(); //current tag is <testcase> or </suite> 324 } 325 xtr.Close(); 326 } 327 } 328 } 329 330 namespace SerializerLib 331 { 332 using System.Xml.Serialization; 333 334 [XmlRootAttribute("suite")] 335 public class Suite 336 { 337 [XmlElementAttribute("testcase")] 338 public TestCase[] items; 339 public void Display() 340 { 341 foreach(TestCase tc in items) 342 { 343 Console.WriteLine(tc.id + " " + tc.bvt + " " + tc.inputs.arg1 + " " + tc.inputs.arg2 + " " + tc.expected); 344 } 345 } 346 347 } 348 349 public class TestCase 350 { 351 [XmlAttributeAttribute()] 352 public string id; 353 [XmlAttributeAttribute()] 354 public string bvt; 355 [XmlElementAttribute("inputs")] 356 public Inputs inputs; 357 public string expected; 358 359 } 360 361 public class Inputs 362 { 363 public string arg1; 364 public string arg2; 365 } 366 } 367 368 namespace Utility 369 { 370 public class TestCase 371 { 372 public string id; 373 public string bvt; 374 public string arg1; 375 public string arg2; 376 public string expected; 377 } 378 379 public class Suite 380 { 381 public System.Collections.ArrayList cases = new System.Collections.ArrayList(); 382 public void Display() 383 { 384 foreach (TestCase tc in cases) 385 { 386 Console.WriteLine(tc.id + " " + tc.bvt + " " + tc.arg1 + " " + tc.arg2 + " " + tc.expected); 387 } 388 } 389 } 390 }