2015-05-20 2 views
1

Я формулирую xmlnodes из цикла. так что это делаетСформулировать хорошо сформированный xml из фрагментов Xml, используя C#

var settings = new XmlWriterSettings(); 
    settings.OmitXmlDeclaration = true; 
    settings.Indent = true; 
    var ns = new XmlSerializerNamespaces(); 
    ns.Add("", ""); 
    foreach (Person human in bar) 
    { 
     var serializer = new XmlSerializer(typeof(Person)); 
     using (var stream = new FileStream(filepath, FileMode.Append)) 
     using (var writer = XmlWriter.Create(stream, settings)) 
     { 
      serializer.Serialize(writer, human, ns); 
     } 
    } 

Он формулирует фрагменты XML, когда цикл выполняется вывод XML, как это

<Person> 
    <Name>mar8a</Name> 
    <Age>11</Age> 
    <Sex>MALE</Sex> 
    <Address>TOP 92 BOTTOM</Address> 
    <SingleYn>false</SingleYn> 
</Person> 
<Person> 
    <Name>mar1a</Name> 
    <Age>1</Age> 
    <Sex>MALE</Sex> 
    <Address>TOP 92 BOTTOM</Address> 
    <SingleYn>false</SingleYn> 
</Person> 
<Person> 
    <Name>mar2a</Name> 
    <Age>11</Age> 
    <Sex>MALE</Sex> 
    <Address>TOP 92 BOTTOM</Address> 
    <SingleYn>false</SingleYn> 
</Person> 
<Person> 
    <Name>mar3a</Name> 
    <Age>1</Age> 
    <Sex>MALE</Sex> 
    <Address>TOP 92 BOTTOM</Address> 
    <SingleYn>false</SingleYn> 
</Person><Person> 
    <Name>mar4a</Name> 
    <Age>11</Age> 
    <Sex>MALE</Sex> 
    <Address>TOP 92 BOTTOM</Address> 
    <SingleYn>false</SingleYn> 
</Person> 
<Person> 
    <Name>mar5a</Name> 
    <Age>11</Age> 
    <Sex>MALE</Sex> 
    <Address>TOP 92 BOTTOM</Address> 
    <SingleYn>false</SingleYn> 
</Person> 
<Person> 
    <Name>mar6a</Name> 
    <Age>11</Age> 
    <Sex>MALE</Sex> 
    <Address>TOP 92 BOTTOM</Address> 
    <SingleYn>false</SingleYn> 
</Person> 
<Person> 
    <Name>mar7a</Name> 
    <Age>11</Age> 
    <Sex>MALE</Sex> 
    <Address>TOP 92 BOTTOM</Address> 
    <SingleYn>false</SingleYn> 
</Person> 
<Person> 
    <Name>mar8a</Name> 
    <Age>11</Age> 
    <Sex>MALE</Sex> 
    <Address>TOP 92 BOTTOM</Address> 
    <SingleYn>false</SingleYn> 
</Person> 

проблема я бегу через то, как изменить его и сделать его аа хорошо сформированный xml с корневым узлом и объявление в конце цикла.

ive попробовал следующую концепцию, но не повезло, потому что это ограничивает меня отсутствием корневых элементов на писателе.

 StringBuilder output = new StringBuilder(); 
     XmlReaderSettings ws = new XmlReaderSettings(); 
     ws.ConformanceLevel = ConformanceLevel.Fragment; 
     String xmlString = 
       @"<Item>test with a child element stuff</Item> 
       <Item>test with a child element stuff</Item>"; 
     // Create an XmlReader 
     using (XmlReader reader = XmlReader.Create(new StringReader(xmlString), ws)) 
     { 
      XmlWriterSettings ws2 = new XmlWriterSettings(); 
      ws2.Indent = true; 
      using (XmlWriter writer = XmlWriter.Create(output, ws2)) 
      { 
       writer.WriteStartDocument(); 
       // Parse the file and display each of the nodes. 
       while (reader.Read()) 
       { 
        switch (reader.NodeType) 
        { 
         case XmlNodeType.Element: 
          writer.WriteStartElement(reader.Name); 
          break; 
         case XmlNodeType.Text: 
          writer.WriteString(reader.Value); 
          break; 
         case XmlNodeType.XmlDeclaration: 
         case XmlNodeType.ProcessingInstruction: 
          writer.WriteProcessingInstruction(reader.Name, reader.Value); 
          break; 
         case XmlNodeType.Comment: 
          writer.WriteComment(reader.Value); 
          break; 
         case XmlNodeType.EndElement: 
          writer.WriteFullEndElement(); 
          break; 
        } 
       } 
       writer.WriteEndDocument(); 

      } 
     } 

Обновление !!

вот код, который сериализация списка моей реализации сериализатора

 public static async Task WriteXMLAsync<T>(this List<T> listRows, T entity, VMEXPORT[] arrVmExport, string filePath) 
     where T : class 
    { 
     XmlWriterSettings Xmlsettings = new XmlWriterSettings(); 
     Xmlsettings.Indent = true; 
     Xmlsettings.OmitXmlDeclaration = false; 
     Xmlsettings.NewLineOnAttributes = true; 
     Xmlsettings.Async = true; 
     Xmlsettings.Encoding = Encoding.UTF8; 
     Xmlsettings.CheckCharacters = false; 

     XmlAttributeOverrides Xmloverrides = new XmlAttributeOverrides(); 
     XmlAttributes Xmlattribs = new XmlAttributes(); 
     Xmlattribs.XmlIgnore = true; 
     Xmlattribs.XmlElements.Add(new XmlElementAttribute("SfiObjectState")); 
     Xmloverrides.Add(typeof(T), "SfiObjectState", Xmlattribs); 


     if (!File.Exists(filePath)) 
     { 
      using (var fileStream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, 4096, true)) 
      { 
       XmlSerializer serializer = new XmlSerializer(typeof(List<T>), Xmloverrides); 
       using (XmlWriter xmlWriter = XmlWriter.Create(fileStream, Xmlsettings)) 
       { 
        serializer.Serialize(xmlWriter, listRows); 
        await xmlWriter.FlushAsync(); 
       } 
      } 
     } 
     else 
     { 

      using (var fileStream = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.None, 4096, true)) 
      { 
       XmlSerializer serializer = new XmlSerializer(typeof(List<T>), Xmloverrides); 
       using (XmlWriter xmlWriter = XmlWriter.Create(fileStream, Xmlsettings)) 
       { 
        serializer.Serialize(xmlWriter, listRows); 
        await xmlWriter.FlushAsync(); 
       } 
      } 


     } 

    } 

И Вот что итерация по методе, описанной выше, реализующим взять и пропустить

public async Task WriteXmlDataAsync<TEntity>(IQueryable<TEntity> listToWrite, [DataSourceRequest]DataSourceRequest dataRequest, 
              int countno, VMEXPORT[] vmExportarr, CancellationToken token, 
              TEntity entity, string csvFileNametx, string XmlFilePathtx) 
     where TEntity : class 
    { 
     dataRequest.GroupingToSorting(); 
     int datapageno = (countno/GeneralConst.L_MAX_EXPORT_REC) + 1; 
     for (int ctrno = 1; ctrno <= datapageno;) 
     { 
      if (token.IsCancellationRequested) 
      { 
       RemoveTask(csvFileNametx); 
       token.ThrowIfCancellationRequested(); 
      } 
      dataRequest.Page = ctrno; 
      dataRequest.PageSize = GeneralConst.L_MAX_EXPORT_REC; 
      var dataSourceResult = listToWrite.ToDataSourceResult(dataRequest); 
      await dataSourceResult.Data.Cast<TEntity>().ToList().WriteXMLAsync(entity, vmExportarr, XmlFilePathtx); 
      ctrno = ctrno + 1; 
      int percentageno = (ctrno * 100)/datapageno; 
      if (percentageno > 100) percentageno = 100; 
      UpdateTask(csvFileNametx, percentageno); 
     } 

    } 
+0

Не можете ли вы просто написать весь список в XML (возможно, вам нужно добавить класс-оболочку, чтобы иметь нужный вам корневой элемент)? –

+0

Мне нужно добавить фрагменты xml в пакетном режиме.(соображения масштабируемости), делающие фрагменты асинхронно, чтобы добавить несколько сотен записей по очереди. если я напишу весь список в моем сценарии, он будет иметь несколько корневых элементов. –

+0

XML, вероятно, не самый лучший формат для данных, которые вы пытаетесь сохранить, чем ... Во всяком случае, ваш образец не записывает корневой узел любого типа ('WriteStartDocument' does not волшебным образом создайте для вас корневой узел). –

ответ

1

Вариант 1

Вы могли бы сделать что-то быстро и грязно, как это после того, как файл XML написано:

public static void AddOuterElement(string fileName, string elementName) 
    { 
     var startElement = string.Format(@"<{0}>", elementName); 
     var endElement = string.Format(@"</{0}>", elementName); 

     var tmpName = Path.GetTempFileName(); 
     try 
     { 
      using (var writer = new StreamWriter(tmpName, false, Encoding.UTF8)) 
      { 
       writer.WriteLine(startElement); 
       foreach (var line in File.ReadLines(fileName)) // Reads lines incrementally rather than all at once. 
        writer.WriteLine(line); 
       writer.WriteLine(endElement); 
      } 
     } 
     catch (Exception ex) 
     { 
      Debug.WriteLine(ex); 
      try 
      { 
       System.IO.File.Delete(tmpName); 
      } 
      catch (Exception) 
      { 
      } 
      throw; 
     } 
     System.IO.File.Delete(fileName); 
     System.IO.File.Move(tmpName, fileName); 
    } 

Это требует записи файла XML дважды.

Вариант 2

Предположим, у вас есть какой-то метод, который может возвращать список вашего Person класса на куски, скажем, со следующей подписью:

IEnumerable<IEnumerable<Person>> GetPeopleInChunks() 
    { 
     // Query the database in chunks of 200 and yield return each list. 
    } 

Затем вы можете использовать следующие классы, адаптированные из this answer, чтобы последовательно сериализовать всех людей в базе данных, не загружая их сразу в память:

// Proxy class for any enumerable with the requisite `Add` methods. 
public class EnumerableProxy<T> : IEnumerable<T> 
{ 
    [XmlIgnore] 
    public IEnumerable<T> BaseEnumerable { get; set; } 

    public void Add(T obj) 
    { 
     throw new NotImplementedException(); 
    } 

    #region IEnumerable<T> Members 

    public IEnumerator<T> GetEnumerator() 
    { 
     if (BaseEnumerable == null) 
      return Enumerable.Empty<T>().GetEnumerator(); 
     return BaseEnumerable.GetEnumerator(); 
    } 

    #endregion 

    #region IEnumerable Members 

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 

    #endregion 
} 

[XmlRoot("People")] 
public class People 
{ 
    [XmlIgnore] 
    public IEnumerable<Person> Results { get; set; } 

    [XmlElement("Person")] 
    public EnumerableProxy<Person> ResultsProxy 
    { 
     get 
     { 
      return new EnumerableProxy<Person> { BaseEnumerable = Results }; 
     } 
     set 
     { 
      throw new NotImplementedException(); 
     } 
    } 
} 

И потом:

public void WriteXml(string fileName) 
    { 
     var people = new People { Results = GetPeopleInChunks().SelectMany(chunk => chunk) }; 
     using (var writer = XmlWriter.Create(fileName)) 
     { 
      new XmlSerializer(typeof(People)).Serialize(writer, people); 
     } 
    } 
+0

это хорошо выглядит. в конце концов, работа будет работать. что я имел в виду, я должен делать это, как будто это количество данных, чтобы избежать исключения oom. Это правильно подает сериализатор на каждую игру getchunks? –

+0

@EduCielo - «это правильно подает сериализатор на каждую игру». И 'SelectMany' делает его похожим на одно перечислимое, а не на кучу кусков. – dbc

+0

объяснил здесь более чистый способ, чем ваш ответ на другой пост. Это делает Xmlserializer более гладким. –

0

Попробуйте что-нибудь, как показано ниже. Вы также должны иметь только один уровень тегов на уровне корня.

  XmlDocument doc = new XmlDocument(); 
      doc.LoadXml(xmlStr); 


      XmlDeclaration xDeclare = doc.CreateXmlDeclaration("1.0", "UTF-8", null); 
      XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", null); 

      doc.InsertBefore(xDeclare, doc.FirstChild); 

      //or 
      string xml1 ="<Root>" + "Your XML" + "</Root>"; 

      //or 
      string xml2 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Root>" + "Your XML" + "</Root>"; 
​ 
+0

Да, в этом подходе я написал файл «огромным» xml-файлом, затем загрузив его в виде строки, а затем добавлю его, чтобы закрыть теги. Я думаю, это не лучшая идея. –

+0

Запишите объявление и корневой тег в начале файла. Затем напишите вам огромные данные в файл. Наконец напишите закрывающий тег перед закрытием файла. Таким образом, вам не нужно открывать, читать и писать огромный файл 2 раза. – jdweng

+0

У вас есть точка в этом, открывая файл 3x? –

0

Предполагая, что все Person узлы находятся в строке некоторого описания, простой способ превратить что в документ будет что-то вроде этого:

XmlDocument oXmlDocument = new XmlDocument(); 
    oXmlDocument.AppendChild(oXmlDocument.CreateXmlDeclaration("1.0", "UTF-8", "")); 

    string sFileContents = "XML Fragments In Here"; 

    XmlNode oRootXmlNode = oXmlDocument.CreateElement("Root"); 
    oRootXmlNode.InnerXml = sFileContents; 

    oXmlDocument.AppendChild(oRootXmlNode); 
    oXmlDocument.Save("XMLFileName.xml"); 

Это может не будет хорошей идеей, если фрагменты окажутся огромными.

Смежные вопросы