按XML元素拆分字符串

时间:2015-10-16 11:57:40

标签: c# string parsing split

我有以下输入字符串,来自10MB文本文件

string data = "0x52341\n0x52341<?xml version=\"1.0\" encoding=\"UTF-8\"?><element1 value=\"3\"><sub>1</sub></element1>0x52341\n0x52341 <element1><sub><element>2</element></sub></element1>0x52341<element2><sub>3</sub‌​‌​></element2> <element2><sub>4</sub></element2>0x4312";

现在我想通过element1element2 XML节点

来创建这个字符串

这种情况下的结果应该是

output[0] = "<element1 value="3"><sub>1</sub></element1>";
output[1] = "<element1><sub><element>2</element></sub></element1>";
output[2] = "<element2><sub>3</sub></element2>";
output[3] = "<element2><sub>4</sub></element2>";

我的efford:

我已经尝试过正则表达式,但是在那个大文件的情况下这很慢,我也试过了

string[] output= input.Split(new string[] { "<element1>", "<element2>" }, StringSplitOptions.None);

string.Split()迂回曲折,因为它抛出了内存异常,并且在分裂时删除了删除者。

问题: 有没有一种简单的方法可以解析我的文本文件中的那些xml元素?

更新 我简化了我的文件,因为我无法在SO中发布整个10MB文件 - 有时xml元素之间有0x1234值,有时候不是

4 个答案:

答案 0 :(得分:3)

如果你能保证每个<elementX></elementX>片段都是格式良好的XML节点(可以这么说),请将整个字符串包装在<elements> ... </elements>中并使用它来处理它标准的.NET方法,无论是XmlDocument,Linq to XML还是其他适合你的方法。

答案 1 :(得分:1)

编辑: 一个更快的替代方案(因为它没有使用正则表达式)不会替换元素内容中的0x ...片段将是以下一个:

string data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>0x52341<element1 value=\"3\"><sub>1</sub></element1>0x234512 <element1><sub><element>2</element></sub></element1>0x52341<element2><sub>3</sub></element2> <element2><sub>4</sub></element2>0x4312";

XmlReaderSettings xrs = new XmlReaderSettings();
xrs.ConformanceLevel = ConformanceLevel.Fragment;
XDocument doc = new XDocument(new XElement("root"));
XElement root = doc.Descendants().First();

using(var ms = new StreamWriter(new MemoryStream()))
{
    ms.Write(data);
    ms.Flush();
    ms.BaseStream.Position = 0;
    using (StreamReader fs = new StreamReader(ms.BaseStream))
    //using (StreamReader fs = new StreamReader("file.xml"))
    {
        using (XmlReader rdr = XmlReader.Create(fs, xrs))
        {
            while (rdr.Read())
            {
                if (rdr.NodeType == XmlNodeType.Element)
                {
                    root.Add(XElement.Load(rdr.ReadSubtree()));
                }
            }
        }
    }
}

您还可以使用另一个StreamReader构造函数直接从该文件中读取(删除StreamWriter部分)

答案 2 :(得分:0)

这是一个可以执行此操作的控制台应用程序:

class Program
{
    static void Main(string[] args)
    {
        string source = "0x52341<element1 value=\"3\"><sub>1</sub></element1>0x234512 <element1><sub><element>2</element></sub></element1>0x52341<element2><sub>3</sub></element2> <element2><sub>4</sub></element2>0x4312";
        List<string> components = new List<string>();
        while (source.Length > 0)
        {
            int start = source.IndexOf('<');
            if (-1 == start)
                break;
            int next = source.IndexOf("0x", start, StringComparison.OrdinalIgnoreCase);
            if (-1 == next)
                break;
            components.Add(source.Substring(start, next - start));
            source = source.Substring(next);
        }
        foreach (string s in components)
            Console.WriteLine(s);
        Console.ReadLine();
    }
}

尝试一下。

答案 3 :(得分:0)

将文件作为流处理 - 查找开始和结束元素,仅解析进程中的那些元素:

  using (var stream = File.OpenRead("..."))
  {
    StringBuilder builder = null;
    StringBuilder xml = null;
    using (var reader = new StreamReader(stream, Encoding.UTF8))
    {
      while (!reader.EndOfStream)
      {
        char c = (char)reader.Read();
        if (c == '<' && builder == null)
        {
          builder = new StringBuilder();
        }
        if (builder != null)
        {
          builder.Append(c);
        }
        if (xml != null)
        {
          xml.Append(c);
        }

        if (c == '>')
        {
          var token = builder.ToString();
          if (xml == null)
          {
            if (token.StartsWith("<element1", StringComparison.Ordinal) || token.StartsWith("<element2", StringComparison.Ordinal))
            {
              xml = new StringBuilder("<?xml version='1.0' encoding='utf-8' ?>");
              xml.Append(token);
            }
          }
          else
          {
            if (token.StartsWith("</element1", StringComparison.Ordinal) || token.StartsWith("</element2", StringComparison.Ordinal))
            {
              XElement element = XElement.Parse(xml.ToString());
              // do something with the element
              xml = null;
            }
          }
          builder = null;
        }
      }
    }
  }