Fork me on GitHub

访问XML的方法

      昨天用wpf的时候要访问xml,弄了很久,所以记录一下。

     C#3.0提供了轻型的XmlReader、XmlWriter类和完全文档对象模式(DOM)的XmlDocument类。这也是我昨天郁闷半天的原因。以前用过XmlTextReader,也没搞太懂,就是找到了方法,贴上代码。看懂下了事。

在这个博客可以找到原理:http://www.cnblogs.com/xdesigner/archive/2008/05/15/1198398.html

整个博客可以看到xml操作方法:http://www.cnblogs.com/surfsky/archive/2007/03/13/673625.html

     先上原理:

     XmlReader是流式处理模型,所谓流式处理是指将XML文档当做一个数据流来进行处理,逐个处理XML文档中的数据。这种模型下,读取快,内存占用少,性能也就好。它的缺点也明显(昨天我就是在这上面闷了很久):1.只能读取不能修改;2.不能使用XPath技术;3.接口简单,处理方法比较少。

System.Xml空间
    以下类适合快速流式读写XML文件(注:DOM适合随机读写)
    XmlReader, XmlWriter,
    XmlTextReader, XmlTextWriter
    XmlValidatingReader, XmlValidatingWriter    添加了DTD和模式验证,因此提供了数据的有效性验证
    XmlNodeReader, XmlNodeWriter                把XmlNode作为其源

      XmlDocument是DOM处理模型,使用文档对象模型的思想解析整个XML文档,在内存中生成一个对象树来表述XML文档。可以使用XmlElement对象来影射XML文档中的一个元素,使用XmlAttribute对象来影射到XML文档中的一个属性。这样通过编程可以方便的操作XML,比如递归遍历XML文档的一部分或全部,可以像树状结构插入,修改或删除XML元素,可以设置XML元素的属性。

       在DOM模式下,我们可以使用XPath技术在XML文档树状结构中进行快速检索和定位,这为处理XML文档带来比较大的方便。

经常用到的几个DOM的类型;

XmlNode 是DOM结构中的所有类型的基础类型,它定义了所有XML节点的通用属性和方法,是XMLDOM的基础。它具有一个ChildNodes属性,表示它所包含的子XML节点。

    XmlAttribute 表示XML属性,它只保存在XmlElement的Attributes 列表中。

    XmlDocument表示XML文档本身,是XMLDOM模型中的顶级对象,它用于对XML文档进行整体的控制,并且是其它程序访问XML文档对象树的唯一入口。

    XmlLinkedNode在XmlNode的基础上实现了访问前后同级节点的方法。

    XmlElement元素表示XML元素。是XMLDOM中使用最多的对象类型。它具有Attributes属性可以处理它所拥有的属性,可以使用ChildNodes属性获得它所有的子节点。并提供了一些添加和删除子节点的方法。

 

 

 

 

 

 

 

 

 

下面看一张XDocument的(有个问题想问,XDocument和XElement的关系是?):

 

再上建议:

  使用XmlDocument:1.传统的DOM方法适用。2.所需的整个文档皆在内存中。3.必须在内存中向前或向后遍历以及更新。

  使用XmlReader/XmlWriter:1.必须适用流方法。2.必须要求进行最快的处理。3.要处理较大的文档并且无法一次性加载全部文档。

  使用XElement/XDocument:1.用代码构建xml声明。2.LINQ的查询能力有助于流方法。3.需要一种针对大多数开发人员的更易读的XML编程语法。

                                         4.要求使用查语义在内存中遍历。

博文后面的代码比较多,我只说我用到的。

XmlReader有个很经典的:

XmlReader reader = xDoc.CreateRedaer();
reader.Settings.CheckCharacters = true;
int level = 0;
while(reader.Reader())
{
  switch(reader.NodeType)
  {
      case XmlNodeType:
           Display(level,"CDATA:{0}",reader.Value);
           break;
      case XmlNodeType.Comment:
           Display(level,"Comment:{0}",reader.Value);
           break;
      case XmlNodeType.DocumentType:
           Display(level,"DOCTYPE:{0}=	   {1}",reader.Name,reader.Value);
           break;
      case XmlNodeType.Element:
           Display(level,"Element:{0}",reader.Name);
           level++;
           while(reader.MoveToNextAttribute())
           {
               Display(level,"ATTRIBUTE:	       {0}='{1}'",reader.Name,reader.Value);
           }
           break;
      case XmlNodeType.EndElement;
           level--;
           break;
      case XmlNodeType.EntityReference:
           Display(level,"ENTITY:{0}",reader.Name);
           break;
      case XmlNodeType.ProcessingInstruction:
           Display(level,"INSTRUCTION:	   {0}={1}",reader.Value);
           break;
      case XmlNodeType.Text;
           Display(level,"TEXT:{0}",reader.Value);
           break;
      case XmlNodeType.XmlDeclaration:
           Display(level,"DECLARATION:                      {0}={1}",reader.Value);
           break;
  }
}

static void Display(int indentLevel,string format,params object[] args)
{
    for(int i=0;i<indentLevel;i++)
         Console.Write(" ");
    Console.WriteLine(format,args)
}
XDocument的(网上有更详细的,这个是我为了解决自己的问题写的,主要是遍历某个节点下的全部子节点):
 XmlDocument xmldoc = new XmlDocument();
            xmldoc.Load(filePath);
            XmlNodeList topM = xmldoc.DocumentElement.ChildNodes;
            foreach (XmlElement element in topM)
            {
                if(element.Name=="Vocabulary")
                {
                    XmlNodeList nodelist = element.ChildNodes;
                    Model.Vocabulary vocabulary = new Model.Vocabulary();
                    foreach (XmlElement el in nodelist)
                    {
                        if (el.Name == "Word")
                            vocabulary.Word = el.InnerText;
                        else if (el.Name == "Explain")
                            vocabulary.Explain = el.InnerText;
                        else if (el.Name == "IsLastSelected")
                            vocabulary.IsLastSelected = el.InnerText=="0"?false:true;
                    }
                    vocabularies.Add(vocabulary);
                }
OK,先到这里,以后碰到问题再补上增删的。

继续:

关于linq to xml的,关于Descentdants函数。具体可以参看:http://www.programbbs.com/doc/4564.htm

Desentdants英文意思是后代,晚辈。也就是这个函数是用于获得某个Element下的指定子Element。

foreach (XElement elem in doc.Elements(\"Customers\").Descendants(\"Customer\"))     
{
    Console.WriteLine(string.Format(
                                 \"Customer ID : {0}, Name : {1}, Address : {2}\", 
                                  elem.Attribute(\"ID\").Value,  
                                  elem.Attribute(\"Name\").Value, 
                                  elem.Attribute(\"Address\").Value)
);
} 
<?xml version=\"1.0\" encoding=\"utf-8\"?> 
<Customers>
<Customer ID=\"A0001\" Name=\"Tom\" Address=\"Taipen\" />  
<Customer ID=\"A0002\" Name=\"Mary\" Address=\"LD\" />  
<Customer ID=\"A0003\" Name=\"Jeff\" Address=\"YW\" /> 
</Customers> 
特别的,当xml中包含了Namespace时,传入的Descendants的指定Element名称必包含Namespace,

Descendants函数接收的是一个XName的元素,它隐含了\算子,显然刚只得到了Element的LocalName。可以这样做:

var cstr = (from s1 in doc.Descendants() where s1.Name.LocalName==\"Connection\" select s1).First();

var cstr = (from s1 in doc.Descendants(doc.Root.Name.Namespace+\"Connection\" select s1).First();

 

继续:Linq to xml 的Elements()函数

(发现很多方法都可以轻松搞定我那个问题)

参考网站:http://www.cnblogs.com/ucetgg/archive/2009/04/23/1441739.html

var name = from nm in xelement.Elements("Employee") where (string)nm.Element("Sex")=="Female" select nm;

 

继续:处理非法字符

XElement和XmlWriter方法:

XElement可以直接处理转义也可以用XCData对象处理。

string invalidChars =@"<>\&";
XElement element = new XElement("Root",
                        new XElement("InvalidChars1",
                            new XCData(invalidChars)),
                        new XElement("InvalidChars2", invalidChars));

InvalidChars1将保存为<![CDATA[<>\&"]>,InvalidChars2将转义存储。

附上转义表:

  <   &lt;

  <   &gt;

  "    &quot;

  '    &apos;

  &   &amp;

  XmlWriter处理可以使用WriteCData方法将非法字符封装在CDATA片段中,另一种使用WriteElementString方法。   

string invalidChars =@"<>\&";
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
using(XmlWriter writer = XmlWriter.Create(Console.Out,settings))
{
writer.WriteStartElement("root");
writer.WriteStartElement("InvalidChars1");
writer.WriteCDate(invalidChars);
writer.WriteEndElement();
writer.WriteElementString("InvalidChars2",invalidChars);
writer.WriteEndElement();
}

XmlDocumenthe和XmlElement处理方法:

放置于CDATA片段中,并添加至XmlElement的InnerXML属性中。

string invalidChars =@"<>\&";
XmlElement invalidElement1 = xmlDoc.CreateElement("InvalidChars1");
invalidElement1.AppendChild(xmlDoc.CreateCDataSection(invalidChars);

通过赋值给InnerText属性令XmlElement类为封装数据。

string invalidChars =@"<>\&";
XmlElement invalidElement2 = xmlDoc.CreateElement("InvalidChars2");
invalidElement2.InnerText = invalidChars;
posted @ 2009-12-29 11:56  idoku  阅读(438)  评论(0编辑  收藏  举报