经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C# » 查看文章
xmlreader与xmlwriter里的几个坑与解决方案
来源:cnblogs  作者:饺子快跑  时间:2019/1/2 9:55:39  对本文有异议

 

加载超过100M的xml文件时(可能不是很常见),XmlDocument这种全部加载到内存里的模式就有点不友好了,耗时长、内存高。

这时用xmlreader就会有自行车换超跑的感觉,但其间遇到几个坑,记录一下。

先看源码,包括dom和sax两种模式的读取和写入

DOM模式:

  1. 1 /// <summary>
  2. 2 /// dom模式创建xml文件
  3. 3 /// </summary>
  4. 4 /// <param name="path"></param>
  5. 5 public void CreateXml_Dom(string path)
  6. 6 {
  7. 7 XmlDocument xmlDocw = new XmlDocument();
  8. 8 //xml头
  9. 9 var xmldecl = xmlDocw.CreateXmlDeclaration("1.0", "utf-8", null);
  10. 10 var root = xmlDocw.CreateElement("root");
  11. 11 root.SetAttribute("Name", "李四");
  12. 12 var test = xmlDocw.CreateElement("test");
  13. 13 root.AppendChild(test);
  14. 14
  15. 15 xmlDocw.AppendChild(xmldecl);
  16. 16 xmlDocw.AppendChild(root);
  17. 17 xmlDocw.Save(path);
  18. 18
  19. 19 //可以通过xmlreader读数据后生成节点
  20. 20 //var node = xmlDocw.ReadNode(rdr);
  21. 21 //root.AppendChild(node);
  22. 22 //或者读取outerxml后作为innerxml写入
  23. 23 //string str = rdr.ReadOuterXml();
  24. 24 //root.InnerXml = str;
  25. 25 }
  26. 26
  27. 27 /// <summary>
  28. 28 /// dom模式读取xml
  29. 29 /// </summary>
  30. 30 /// <param name="path"></param>
  31. 31 public void ReadXml_Dom(string path)
  32. 32 {
  33. 33 XmlDocument xmlDocr = new XmlDocument();
  34. 34 xmlDocr.Load(path);
  35. 35 var root = xmlDocr.DocumentElement;
  36. 36 string str = root.GetAttribute("Name");
  37. 37 Console.WriteLine(str);
  38. 38 }

 

SAX(simple API for XML)模式:几种错误也都用注释标注出来了

  1. 1 /// <summary>
  2. 2 /// xmlwriter创建xml文件
  3. 3 /// </summary>
  4. 4 /// <param name="path"></param>
  5. 5 public void CreateXml_Sax(string path)
  6. 6 {
  7. 7 //filestream没问题
  8. 8 //FileStream stream = new FileStream(path,FileMode.Create);
  9. 9 //会出现编码一直是utf-16问题
  10. 10 //StringBuilder stream = new StringBuilder();
  11. 11 MemoryStream stream = new MemoryStream();
  12. 12 XmlWriterSettings settings = new XmlWriterSettings();
  13. 13 //Encoding.UTF8这个会报错,字节顺序标记
  14. 14 settings.Encoding = new UTF8Encoding(false);
  15. 15 XmlWriter xw = XmlWriter.Create(stream, settings);
  16. 16 //XmlTextWriter xw = new XmlTextWriter(stream, new UTF8Encoding(false));
  17. 17
  18. 18 //写入声明
  19. 19 xw.WriteStartDocument();
  20. 20
  21. 21 xw.WriteStartElement("root");
  22. 22 xw.WriteAttributeString("Name", "张三");
  23. 23 //可以通过xmlreader读数据后直接写入
  24. 24 //xw.WriteNode(rdr);
  25. 25 xw.WriteStartElement("test");
  26. 26 xw.WriteEndElement();
  27. 27
  28. 28 xw.WriteEndElement();
  29. 29
  30. 30 xw.WriteEndDocument();
  31. 31 xw.Close();
  32. 32
  33. 33 string xmlstr = Encoding.UTF8.GetString(stream.ToArray());
  34. 34 stream.Close();
  35. 35 XmlDocument xmlDocw = new XmlDocument();
  36. 36 xmlDocw.LoadXml(xmlstr);
  37. 37 xmlDocw.Save(path);
  38. 38 }
  39. 39
  40. 40 /// <summary>
  41. 41 /// xmlreader读取xml
  42. 42 /// </summary>
  43. 43 /// <param name="path"></param>
  44. 44 public void ReadXml_Sax(string path)
  45. 45 {
  46. 46 XmlDocument xmlDocw = new XmlDocument();
  47. 47 XmlReaderSettings rsettings = new XmlReaderSettings();
  48. 48 rsettings.IgnoreComments = true;
  49. 49 rsettings.IgnoreWhitespace = false;
  50. 50 rsettings.CheckCharacters = false;
  51. 51 //默认的xmlreader不读取内容中的回车换行\r\n
  52. 52 //(XmlReader rdr = XmlReader.Create(path,rsettings))
  53. 53 using (XmlTextReader rdr = new XmlTextReader(path))
  54. 54 {
  55. 55 rdr.WhitespaceHandling = WhitespaceHandling.Significant;
  56. 56 string eleName = "";
  57. 57 while (rdr.Read())
  58. 58 {
  59. 59 if (rdr.NodeType == XmlNodeType.Element)
  60. 60 {
  61. 61 //节点名称
  62. 62 eleName = rdr.Name;
  63. 63 //节点深度
  64. 64 int dp = rdr.Depth;
  65. 65 //是否空节点,表示<elememt/> 不是<element></element>
  66. 66 bool needend = rdr.IsEmptyElement;
  67. 67 for (int i = 0; i < rdr.AttributeCount; i++)
  68. 68 {
  69. 69 rdr.MoveToAttribute(i);
  70. 70 Console.WriteLine(rdr.Name+":"+rdr.Value);
  71. 71 }
  72. 72 //可以直接读取节点所有的数据.可以用readNode读取
  73. 73 //rdr.EOF判定,不然会跳过节点
  74. 74 //rdr.ReadOuterXml();
  75. 75 }
  76. 76 else if (rdr.NodeType == XmlNodeType.EndElement)
  77. 77 {
  78. 78 eleName = rdr.Name;
  79. 79 }
  80. 80 }
  81. 81 }
  82. 82 }

xmlreader和xmldocument(xmlwriter)组合一起用对大型xml进行拆分读取,十分有效。 

 

下面是遇到的问题:

1.xmlwriter后xml文件头始终是utf-16

这是用StringBuilder才会有的问题,改用FileStream、MemoryStream等就好了。

 

2.(UTF8)改用MemoryStream后,形成的xml字符串通过XMLDocument.LoadXml时报错

XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.UTF8;

最终发现默认的Encoding.UTF8是带有字节顺序标记的,要用new UTF8Encoding(false);

通过监视区代码可以看到,xmlstr[0]是65279,修改后就对了变成60'<'。

 


3.xmlreader默认不读取内容中的回车换行,读进来就是个空格。

第二个直接回车换行就是读不进来,用xmldocument可以读到两个,xmlreader就是读取不到。

 

   期间一直在找设置,比如IgnoreWhitespace等,发现都没有用,还是不读。

 XmlReaderSettings rsettings = new XmlReaderSettings();
    rsettings.IgnoreWhitespace = false;

 最后在stackoverflow上找到答案(注1),不能用XmlReader rdr = XmlReader.Create(path),用XmlTextReader就好了。

 

 

 

注1:不读回车换行问题 https://stackoverflow.com/questions/1793908/xmlreader-newline-n-instead-of-r-n

This is because the XmlTextReader has a normalization setting defaulted to false unlike XmlReader.Create which always normalizes newlines no matter what. 

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号