反序列化XML文档,跟踪订单

时间:2018-04-03 17:26:47

标签: c# xml-parsing

我正在使用XMLSerialization工具解析XML文档。示例XML文件由paragraphsstring)和tables组成,它们是复杂的XML类型。 Tables由一系列row组成,其中包含一系列entrystring

我需要跟踪每个table相对于每个paragraph的位置。有没有办法在XMLSerialization工具解析时捕获每个table的位置?或者我是否需要使用[XMLAnyElement]等结构并按顺序解析每个paragraphtable以跟踪table位置?我宁愿避免这种方法,因为我的真实XML文件有许多级别需要手动解析。我有一种感觉,我错过了一些非常明显的东西,但我一直在搜索并尝试多种方法,但没有直接的解决方案。

这是我的基本代码:

using System.Xml;
using System.Xml.Serialization;
using System.IO;

namespace XMLDeserializeTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string file = Environment.CurrentDirectory + @"\test.xml";

            test testClass = Deserialize(file);

        }

        static test Deserialize(string url)
        {
                XmlSerializer reader =
                    new XmlSerializer(typeof(test));
                StreamReader stream = new StreamReader(url);
                return reader.Deserialize(stream) as test;         
        }

    }

    public class test
    {
        [XmlElement("paragraph")]
        public List<string> paragraphs { get; set; }

        [XmlElement("table")]
        public List<Table> tables { get; set; }

        public test()
        {

        }

    }

    public class Table
    {
        [XmlElement("row")]
        public List<Row> rows { get; set; }

        public int nodeNumber { get; set; }  // This is what needs to be tracked

        public Table()
        {

        }
    }

    public class Row
    {
        [XmlElement("entry")]
        public List<string> entries { get; set; }

        public Row()
        {

        }
    }

我的示例XML:

<?xml version="1.0" encoding="utf-8" ?>
<test>
  <paragraph>Here is some text.</paragraph>
  <paragraph>Here is some more text. The table follows this paragraph.</paragraph>
  <table>
       <row>
          <entry>1</entry>
          <entry>2</entry>
          <entry>3</entry>
        </row>
        <row>
          <entry>4</entry>
          <entry>5</entry>
          <entry>6</entry>
        </row>
  </table>
  <paragraph>This is the last paragraph.  This comes after the table.</paragraph>  
</test>

我想出了一个使用XDocument的解决方案,但它看起来很笨拙:

XDocument Xdoc = XDocument.Load(file);                 
int numParagraphs = 0;
int tableNumber = 0;
foreach(XElement item in Xdoc.Root.Descendants())
   {
      if (item.Name.LocalName.Equals("paragraph"))

   {
        numParagraphs++;
   }
      else if (item.Name.LocalName.Equals("table"))
      {
         testClass.tables[tableNumber].nodeNumber = numParagraphs;
         tableNumber++;
      }
   }

1 个答案:

答案 0 :(得分:1)

一个选项只是在序列化时将表的段落“index”序列化为XML。这样你就不必做任何自定义的事情了。

但是,要使用XmlSerializer执行您要查找的内容,您可以使用UnknownElement事件自行处理某些元素类型的反序列化。请注意,已从测试类中删除了XmlElement属性,以便处理表和段落元素。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;

namespace XMLDeserializeTest
{
    class Program
    {
        static int paragraphCount = 0;
        static void Main(string[] args)
        {
            string file = Environment.CurrentDirectory + @"\test.xml";

            paragraphCount = 0;
            test testClass = Deserialize(file);

        }

        static test Deserialize(string url)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(test));
            serializer.UnknownElement += serializer_UnknownElement;
            StreamReader stream = new StreamReader(url);
            return serializer.Deserialize(stream) as test;
        }

        static void serializer_UnknownElement(object sender, XmlElementEventArgs e)
        {            
            test t = (test)e.ObjectBeingDeserialized;

            if (e.Element.Name == "table")
            {
                var s = new XmlSerializer(typeof(Table));
                var sr = new StringReader(e.Element.OuterXml);
                Table newTable = s.Deserialize(sr) as Table;               
                newTable.nodeNumber = paragraphCount;
                t.tables.Add(newTable);                
            }
            else if (e.Element.Name == "paragraph")
            {
                String paragraphText = e.Element.InnerText;
                t.paragraphs.Add(paragraphText);
                paragraphCount++;
            }
        }

    }

    public class test
    {
        public List<string> paragraphs { get; set; }
        public List<Table> tables { get; set; }

        public test()
        {

        }

    }

    [Serializable, XmlRoot("table")]
    public class Table
    {
        [XmlElement("row")]
        public List<Row> rows { get; set; }

        public int nodeNumber { get; set; }  // This is what needs to be tracked

        public Table()
        {

        }
    }

    [Serializable, XmlRoot("row")]
    public class Row
    {
        [XmlElement("entry")]
        public List<string> entries { get; set; }

        public Row()
        {

        }
    }
}