使用 c# 从 Xml 片段制定格式良好的 xml

Formulate a well-formed xml from Xml fragments using c#

我正在从循环中制定 xml 节点。所以它的作用是

   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,在循环末尾有根节点和声明。

我尝试了以下概念,但没有成功,因为它限制我不能在 writer 上写任何根元素。

        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();
                }
            }


        }

    }

下面是对上述实现 take 和 skip 的方法进行迭代的内容

 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);
        }

    }

试试下面的方法。您还需要在根级别只有一个级别的标签。

            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>"; 
​

选项 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

假设您有一些方法可以 return 以块的形式列出您的 Person class,例如使用以下签名:

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

然后您可以使用以下 class 改编自 的 es 顺序序列化数据库中的所有人员,而无需一次将它们全部加载到内存中:

// 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);
        }
    }

假设您所有的 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");

如果碎片最终变得巨大,这可能不是一个好主意。