zoukankan      html  css  js  c++  java
  • 《软件测试自动化之道》读书笔记 之 XML测试

    《软件测试自动化之道》读书笔记 之 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>
    View Code

    测试程序


     返回

    本章给出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 }
    View Code

    通过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     }
    View Code

    分析:

    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         }
    View Code

    分析:

    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         }
    View Code

    分析:

    • 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 }
    View Code

    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         }
    View Code

    分析:

    通过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         }
    View Code

    分析:

    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("
    ==========================================");
     6                 Console.WriteLine("Table= " + dt.TableName + "
    ");
     7                 foreach (DataColumn dc in dt.Columns)
     8                     Console.Write("{0,-14}", dc.ColumnName);
     9                 Console.WriteLine("
    ------------------------------------------");
    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("
    ==========================================");
    17             }
    18             foreach (DataRelation dr in ds.Relations)
    19             {
    20                 Console.WriteLine("
    
    Relations:");
    21                 Console.WriteLine(dr.RelationName+"
    
    ");
    22             }
    23         }
    View Code

    图1 DataSet信息

    通过XSD Schema对XML文件进行验证

    示例代码:

     1         private static void VerifyByXsdSchema(string tcPath)
     2         {
     3             XmlSchemaCollection xsc = new XmlSchemaCollection();
     4             xsc.Add(null, @"....	estCases.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         }
    14 
    15         private static void ValidationCallBack(object sender, ValidationEventArgs ea)
    16         {
    17             Console.WriteLine("Validation error: " + ea.Message);
    18             Console.ReadLine();
    19         }
    View Code

    分析:

    通过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>
    View Code

    修改后的版本:

     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>
    View Code

    示例代码:

    ‘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>
    View Code

    UpdateXMLByXSLT()方法代码:

    1         private static void UpdateXMLByXSLT(string tcPath)
    2         {
    3             XslTransform xst = new XslTransform();
    4             xst.Load(@"....	estCasesModifier.xslt");
    5             xst.Transform(tcPath, @"....	estCasesModifier.xml");
    6             Console.WriteLine("Done. New XML file is 'testCasesModifier.xml'");
    7         }
    View Code

    通过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         }
    View Code

    结果‘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>
    View Code

    比较两个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         }
    View Code

    分析:

    通过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         }
    View Code

    分析:

    编写软件测试时,可能需要对实际的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>
    View Code

    第二个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>
    View Code

    示例代码:

     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("
    ==============
    ");
    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         }
    View Code

    分析:

    通过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
    ");
     22             string tcPath = @"....	estCases.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("
    Done");
     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("
    ==============
    ");
     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(@"....	estCasesModifier.xslt");
    164             xst.Transform(tcPath, @"....	estCasesModifier.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, @"....	estCases.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("
    ==========================================");
    193                 Console.WriteLine("Table= " + dt.TableName + "
    ");
    194                 foreach (DataColumn dc in dt.Columns)
    195                     Console.Write("{0,-14}", dc.ColumnName);
    196                 Console.WriteLine("
    ------------------------------------------");
    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("
    ==========================================");
    204             }
    205             foreach (DataRelation dr in ds.Relations)
    206             {
    207                 Console.WriteLine("
    
    Relations:");
    208                 Console.WriteLine(dr.RelationName+"
    
    ");
    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 }
    View Code
  • 相关阅读:
    mysql命令行备份数据库
    js关闭当前页面的几种方式
    Linux添加FTP用户并设置权限
    在Activity的Title中加入进度条
    android例子程序(ApiDemo)的简单分类整理
    使用WindowManager窗口管理员,把View显示在屏幕中间
    android手动调用振动器(Vibrator)
    android 监听SDCard安装和卸载的代码片段(测试通过)
    android Paint和Color类介绍 使用示例
    GC_EXTERNAL_ALLOC freed 与 GC_EXPLICIT freed 是什么?
  • 原文地址:https://www.cnblogs.com/Ming8006/p/4011113.html
Copyright © 2011-2022 走看看