【问题标题】:XML generation using c#使用 C# 生成 XML
【发布时间】:2020-04-06 12:28:20
【问题描述】:

我的目标是生成这种格式的xml结构

<?xml version='1.0' encoding='UTF-8'?>
<return xmlns:rmas="value here" xmlns:xsi="value here" xsi:noNamespaceSchemaLocation="value here">
   <header>
      <return-code>""</return-code>
      <return-desc>""</return-desc>
      <as-at-date>""</as-at-date>
      <operator-code>""</operator-code>
   </header>
   <body>
         <scheme>
           <code>10050</code>
              <employer>
                    <empr-code></empr-code>
                    <data>
                       <serial-no />
                       <pin />
                       <employer-contribution />
                       <employee-contribution />
                       <voluntary-contribution />
                       <total-contribution />
                    </data>
               </employer>
        </scheme>
        <scheme>
           <code>10100</code>
              <employer>
                    <empr-code></empr-code>
                    <data>
                       <serial-no />
                       <pin />
                       <employer-contribution />
                       <employee-contribution />
                       <voluntary-contribution />
                       <total-contribution />
                    </data>
               </employer>
          </scheme>
          [...]
    </body>
  </return>

这是我正在消费的数据样本

scheme-code emp-code        pin            empr-contr   empyee-contr    total   total-vol-cont
10050       PR0000395010    PEN200386572133 54777.28    43821.82       108599.1  10000  
10050       PR0000679771    PEN200629902715 65528.34    0              215528.34 150000 
10050       PR0000007340    PEN200629902715 0           65528.34       215528.34 150000 
10050       PU000035E001    PEN100786299723 10570.34    10570.34       21140.68  0      
10050       TCF000615630    PEN100786299723 12060.15    12060.16       24120.31  0      
10050       TCF000615630    PEN100786299723 12204.98    12204.99       24409.97  0      
10050       PR0000615630    PEN100144364216 10945.19    13681.49       24626.68  0      
10050       PR0000615630    PEN100453089112 14319.32    17899.15       32218.47  0      
10050       PR0000615630    PEN200742682512 13116.33    16395.41       29511.74  0      
10100       PRTEMP005022    PEN100940140007 792         990            1782      0  
10100       PRTEMP005022    PEN100799131715 2375        2970           5345      0
10100       PRTEMP005022    PEN100799212715 831.6       1039.5         1871.1    0  

在正文标签中,我想首先按方案代码和代码内部对数据进行分组,按该方案中的 emp 代码对数据进行分组,然后按数据(pin,empr-contr, empyee-contr...) 具有 empr 代码。每个数据标签的序列号(整数)将为 0,1,2,3....T999,具体取决于父雇主标签中的数据标签数量。请参阅下面的更多示例

<scheme>
  <code>10050</code>
  [...]
  <employer>
      <empr-code>PR0000615630</empr-code>
         <data>
            <serial-no>1</serial-no>
            <pin>PEN100144364216</pin>
            <employer-contribution>10945.19</employer-contribution>
            <employee-contribution>13681.49</employee-contribution>
            <voluntary-contribution>0.00</voluntary-contribution>
            <total>32218.47</total>
         </data>
         <data>
            <serial-no>2</serial-no>
            <pin>PEN100453089112</pin>
            <employer-contribution>14319.32</employer-contribution>
            <employee-contribution>17899.15/employee-contribution>
            <voluntary-contribution>0.00</voluntary-contribution>
            <total>32218.47</total>
         </data>
      <data>
         <serial-no>T9999</serial-no>
         <pin>PEN200742682512</pin>
         <employer-contribution>13116.33</employer-contribution>
         <employee-contribution>16395.41</employee-contribution>
         <voluntary-contribution>0.00</voluntary-contribution>
         <total>29511.74</total>
      </data>
 </employer>
 [...]
</scheme>

如何使用 XMLDocument 或 XMLWriter 生成它

【问题讨论】:

  • 您应该创建一个类结构来表示 XML。然后从数据库中读取数据并用数据填充类对象,然后将其序列化为 XML。 docs.microsoft.com/en-us/dotnet/standard/serialization/…
  • 在这种情况下创建一个类只会使代码加倍,因为您必须在导出 xml 之前填充类。 xml 中的后代数量很多,因此有很多类。输入是一个平面表,手动解析要容易得多。没有自动生成类的架构。

标签: c# sql-server xml xml-parsing


【解决方案1】:

尝试以下 xml linq。我将您的输入文件放入一个文本文件,然后读入 DataTable。然后从表中创建 XML:

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

namespace ConsoleApplication1
{
    class Program
    {

        const string INPUT_FILENAME = @"c:\temp\test.txt";
        const string OUTPUT_FILENAME = @"c:\temp\test.xml";
        static DataTable dt = new DataTable();
        static XDocument doc;
        static void Main(string[] args)
        {
            ReadData(INPUT_FILENAME);
            dt = dt.AsEnumerable()
                .OrderBy(x => x.Field<string>("scheme-code"))
                .ThenBy(x => x.Field<string>("emp-code"))
                .ThenBy(x => x.Field<string>("pin"))
                .CopyToDataTable();

            CreateXml();
            doc.Save(OUTPUT_FILENAME);

        }
        static void ReadData(string filename)
        {
            int rowNumber = 0;
            string line = "";
            StreamReader reader = new StreamReader(INPUT_FILENAME);

            while ((line = reader.ReadLine()) != null)
            {
                string[] splitData = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToArray();

                if (++rowNumber == 1)
                {
                    for (int i = 0; i < splitData.Length; i++)
                    {
                        if (i < 3)
                        {
                            dt.Columns.Add(splitData[i], typeof(string));
                        }
                        else
                        {
                            dt.Columns.Add(splitData[i], typeof(decimal));
                        }
                    }
                }
                else
                {
                    DataRow newRow = dt.Rows.Add();
                    for (int i = 0; i < splitData.Length; i++)
                    {
                        if (i < 3)
                        {
                            newRow[i] = splitData[i];
                        }
                        else
                        {
                            newRow[i] = decimal.Parse(splitData[i]);
                        }
                    }
                }
            }
            reader.Close();
        }
        static void CreateXml()
        {
            string xmlns_rmas = "value here";
            string xmlns_xsi = "value here";
            string xmlns_noNamespaceSchemaLocation = "value here";
            string xmlIdentFormat =
                "<?xml version='1.0' encoding='UTF-8'?>" +
                "<return" +
                    " xmlns:rmas=\"{0}\"" +
                    " xmlns:xsi=\"{1}\"" +
                    " xsi:noNamespaceSchemaLocation=\"{2}\">" +
                "</return>";
            string xmlIdent = string.Format(xmlIdentFormat, xmlns_rmas, xmlns_xsi, xmlns_noNamespaceSchemaLocation);
            doc = XDocument.Parse(xmlIdent);

            XElement _return = doc.Root;

            string returnCode = "";
            string returnDesc = "";
            DateTime date = DateTime.Now;
            string operatorCode = "";
            XElement header = new XElement("header", new object[] {
                new XElement("return-code", returnCode),
                new XElement("return-desc", returnDesc),
                new XElement("as-at-date", date),
                new XElement("operator-code", operatorCode)
            });
            _return.Add(header);

            XElement body = new XElement("body");
            _return.Add(body);


            foreach(var schemeGroup in dt.AsEnumerable().GroupBy(x => x.Field<string>("scheme-code")))
            {
                XElement scheme = new XElement("scheme");
                body.Add(scheme);
                XElement code = new XElement("code", schemeGroup.Key);
                scheme.Add(code);
                foreach(var empCodeGroup in schemeGroup.GroupBy(y => y.Field<string>("emp-code")))
                {
                    XElement employer = new XElement("employer");
                    scheme.Add(employer);
                    int serialNumber = 0;

                    foreach(var pinGroup in empCodeGroup.GroupBy(y => y.Field<string>("pin")))
                    {
                        if (serialNumber == 0)
                        {
                            XElement emprCode = new XElement("empr-code", empCodeGroup.Key);
                            employer.Add(emprCode);
                        }
                        foreach (DataRow row in pinGroup)
                        {

                            XElement data = new XElement("data");
                            employer.Add(data);
                            if ((empCodeGroup.Count() > 1) && (serialNumber == empCodeGroup.Count() - 1))
                            {
                                data.Add(new XElement("serial-no", "T999"));
                            }
                            else
                            {
                                data.Add(new XElement("serial-no", serialNumber));
                            }

                            data.Add(new XElement("pin", pinGroup.Key));
                            data.Add(new XElement("employer-contribution", row.Field<decimal>("empr-contr")));
                            data.Add(new XElement("employee-contribution", row.Field<decimal>("empyee-contr")));
                            data.Add(new XElement("voluntary-contribution", row.Field<decimal>("total-vol-cont")));
                            data.Add(new XElement("total-contribution", row.Field<decimal>("total")));

                            serialNumber++;
                        }

                    }
                }
            }
        }
    }

}

【讨论】:

  • 看看我真正想要的。非常感谢您的帮助。这些是我的观察。请协助:(a)“pin”字段与“emp-code”相同。 (b) emp-code 标记/元素不应在数据标记/元素内 (c) 方案中具有重复值的 emp-code 应具有重复次数的数据标记。即雇主代码“PR0000615630”应该有 3 个数据标签/元素,序列号为 1,2 和 T999,因为它在方案代码中重复了 3 次。序列号不应该继续到下一个雇主标签/元素,而是应该开始一个新的序列。非常感谢
  • 我怎样才能感谢你。你是一个救生员。我想在雇主标签中只有一个 emp-code 用于 emp-code,其值在方案中重复,然后在数据标签/元素中将最后一个序列号作为 T999(如果它们不止一个)。有可能吗?
  • 再次非常简单。这些数据必须是真正的旧数据。我没有见过 T999,因为他们停止使用边缘有孔的高速打印机。
  • 如果您使用的是 SQL Server,您可以使用数据适配器来填充数据表,而不是从文本文件中读取。其余代码将是相同的
  • 再次阅读帖子后,我更新了代码以从零开始序列号。
【解决方案2】:

将数据加载到 DataSet 并使用 Write XML。这是您可以尝试的最简单的方法

DataSet oDsData = new DataSet();
oDsData.WriteXml("path", XmlWriteMode.WriteSchema);

【讨论】:

  • 感谢您的意见,但它将如何处理内部标签/元素?
【解决方案3】:

如果您的数据位于 MSSQL 服务器中,这可能是一种解决方案。我假设您的数据位于数据库中的表 (##tmp_test) 中。

    public string GetXML()
    {
        XmlDocument document = new XmlDocument();
        XmlDeclaration xmlDeclaration = document.CreateXmlDeclaration("1.0", "UTF-8", null);

        XmlElement root = document.DocumentElement;
        document.InsertBefore(xmlDeclaration, root);
        var returnElement =  document.CreateElement( "return");
        returnElement.SetAttribute("xmlns:rmas", "value here");
        returnElement.SetAttribute("xmlns:xsi", "value here");
        returnElement.SetAttribute("noNamespaceSchemaLocation", "value here");

        var header = document.CreateElement("header");
        var rc = document.CreateElement("return-code");
        rc.InnerText = "\"\"";
        header.AppendChild(rc);
        var rd = document.CreateElement("return-desc");
        rd.InnerText = "\"\"";
        header.AppendChild(rd);
        var aad = document.CreateElement("as-at-date");
        aad.InnerText = "\"\"";
        header.AppendChild(aad);
        var oc = document.CreateElement("operator-code");
        oc.InnerText = "\"\"";
        header.AppendChild(oc);
        returnElement.AppendChild(header);

        var body = document.CreateElement("body");
        body.InnerXml = GetBodyXML();

        returnElement.AppendChild(body);

        document.AppendChild(returnElement);

        return document.OuterXml;
    }

    private string GetBodyXML()
    {
        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            connection.Open();
            using (SqlCommand command = new SqlCommand())
            {
                command.Connection = connection;
                command.CommandText = @"
                    SELECT 1 AS Tag
                        ,NULL AS Parent
                        ,[Scheme].[scheme-code] AS [scheme!1!code!ELEMENT]
                        ,NULL AS [employer!2!empr-code!ELEMENT]
                        ,NULL AS [data!3!serial-no!ELEMENT]
                        ,NULL AS [data!3!pin!ELEMENT]
                        ,NULL AS [data!3!employer-contribution!ELEMENT]
                        ,NULL AS [data!3!employee-contribution!ELEMENT]
                        ,NULL AS [data!3!voluntary-contribution!ELEMENT]
                        ,NULL AS [data!3!total!ELEMENT]
                    FROM ##tmp_test [Scheme]

                    UNION

                    SELECT 2 AS Tag
                        ,1 AS Parent
                        ,[Scheme].[scheme-code] AS code
                        ,[Scheme].[emp-code] AS [empr-code]
                        ,NULL AS [serial-no]
                        ,NULL AS pin
                        ,NULL AS [employer-contribution]
                        ,NULL AS [employee-contribution]
                        ,NULL AS [voluntary-contribution]
                        ,NULL AS [total]
                    FROM ##tmp_test [Scheme]

                    UNION

                    SELECT 3 AS Tag
                        ,2 AS Parent
                        ,[Scheme].[scheme-code] AS code
                        ,[Scheme].[emp-code] AS [empr-code]
                        ,ROW_NUMBER() OVER (
                            PARTITION BY [Scheme].[scheme-code]
                            ,[Scheme].[emp-code] ORDER BY pin
                            ) AS [serial-no]
                        ,[Scheme].pin AS [pin]
                        ,[Scheme].[empr-contr] AS [employer-contribution]
                        ,[Scheme].[empyee-contr] AS [employee-contribution]
                        ,[Scheme].[total-vol-cont] AS [voluntary-contribution]
                        ,[Scheme].total AS [total]
                    FROM ##tmp_test [Scheme]
                    ORDER BY [scheme!1!code!ELEMENT]
                        ,[employer!2!empr-code!ELEMENT]
                    FOR XML EXPLICIT
                    ";
                //Better approach to read all xml - https://stackoverflow.com/a/40775242/1010395
                using (XmlReader xmlReader = command.ExecuteXmlReader())
                {
                    XPathDocument xp = new XPathDocument(xmlReader);
                    XPathNavigator xn = xp.CreateNavigator();
                    return xn.OuterXml;
                }
            }
        }
    }

【讨论】:

  • 我会尽快反馈
  • 我遇到了这个错误:无效的列名方案!1!code!ELEMENT
  • @hopeforall 您在哪一行收到此错误?查看运行Sql Fiddle Query
猜你喜欢
  • 2012-07-24
  • 1970-01-01
  • 1970-01-01
  • 2011-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多