[C#]利用 Using 縮排程式碼

  • 4689
  • 0

[C#]利用 Using 縮排程式碼

常遇到要將資料輸出成 XML 格式的需求,使用 .Net 內建的 XmlWriter 寫出來的程式碼太平不易讀,倘若要求的 XML 格式稍微複雜一點,轉檔的程式也就跟著變的更難以閱讀。

也曾試過自己手動加上縮排,但常一不注意就被 IDE 很貼心的自動重排了,以下就利用 using 、Extension 等技巧來克服此問題。

 

很平滑的程式碼


            {
                w.WriteStartElement("Request");
                w.WriteStartElement("Access");
                w.WriteStartElement("Authentication");
                w.WriteEndElement();
                w.WriteStartElement("Connection");
                w.WriteEndElement();
                w.WriteStartElement("Organization");
                w.WriteEndElement();
                w.WriteStartElement("Locale");
                w.WriteEndElement();
                w.WriteEndElement();
                w.WriteStartElement("RequestContent");
                w.WriteEndElement();
                w.WriteEndElement();
            }

改善後的程式碼


{
    using (w.Element("Request"))
    {
        using (w.Element("Access"))
        {
            using (w.Element("Authentication")) { }
            using (w.Element("Connection")) { }
            using (w.Element("Organization")) { }
            using (w.Element("Locale")) { }
        }
        using (w.Element("RequestContent"))
        {
        }
    }
}

縮排後的程式碼看起來就跟輸出的 XML 結構相仿。

 

測試程式及測試資料


{
    var ds = CreateTestDataSet();
    var data = ConvertToXmlFormat(ds, "Master");
    Console.WriteLine(data);
    Console.ReadLine();
}
private static DataSet CreateTestDataSet()
{
    var master = new DataTable { TableName = "Master" };
    AddColumns(master, "key", "number", "time");
    master.Rows.Add("10","2048","2013-12-31 23:59:59");
    var detailA = new DataTable { TableName = "DetailA"};
    AddColumns(detailA, "key", "item", "qty");
    detailA.Rows.Add("10", "Coke", 10);
    detailA.Rows.Add("10", "Cookie", 100);
    var detailB = new DataTable { TableName = "DetailB"};
    AddColumns(detailB, "key", "note");
    detailB.Rows.Add("10", "test1...");
    detailB.Rows.Add("10", "test2...");
    detailB.Rows.Add("10", "test3...");
    var ds = new DataSet();
    ds.Tables.AddRange(new[] { master, detailA, detailB });
    return ds;
}
private static void AddColumns(DataTable t, params string[] colNames)
{
    foreach (var col in colNames)
        t.Columns.Add(col);
}

執行的結果


<Request>
  <Access>
    <Authentication user="user" password="password" />
    <Connection application="" source="" />
    <Organization name="GAME" />
    <Locale language="zh-tw" />
  </Access>
  <RequestContent>
    <Document>
      <RecordSet id="1">
        <Master name="Master">
          <Record>
            <Field name="key" value="10" />
            <Field name="number" value="2048" />
            <Field name="time" value="2013-12-31 23:59:59" />
          </Record>
        </Master>
        <Detail name="DetailA">
          <Record>
            <Field name="key" value="10" />
            <Field name="item" value="Coke" />
            <Field name="qty" value="10" />
          </Record>
          <Record>
            <Field name="key" value="10" />
            <Field name="item" value="Cookie" />
            <Field name="qty" value="100" />
          </Record>
        </Detail>
        <Detail name="DetailB">
          <Record>
            <Field name="key" value="10" />
            <Field name="note" value="test1..." />
          </Record>
          <Record>
            <Field name="key" value="10" />
            <Field name="note" value="test2..." />
          </Record>
          <Record>
            <Field name="key" value="10" />
            <Field name="note" value="test3..." />
          </Record>
        </Detail>
      </RecordSet>
    </Document>
  </RequestContent>
</Request>

 

核心程式 (要改善的目標物)


{
    using (var mem = new MemoryStream())
    {
        var settings = new XmlWriterSettings();
        settings.Indent = true;
        using (var w = XmlWriter.Create(mem, settings))
        {
            using (w.Element("Request"))
            {
                WriteAccessNode(w);
                AddContentNode(w, dataSet, masterTableName);
            }
        }
        return Encoding.UTF8.GetString(mem.ToArray());
    }
}

private static void WriteAccessNode(XmlWriter w)
{
    using (w.Element("Access"))
    {
        using (w.Element("Authentication"))
        {
            w.Attribute("user", "user");
            w.Attribute("password", "password");
        }
        using (w.Element("Connection"))
        {
            w.Attribute("application", "");
            w.Attribute("source", "");
        }
        using (w.Element("Organization"))
        {
            w.Attribute("name", "GAME");
        }
        using (w.Element("Locale"))
        {
            w.Attribute("language", "zh-tw");
        }
    }
}

private static void AddContentNode(XmlWriter w, DataSet dataSet, string masterTableName)
{
    using (w.Element("RequestContent"))
    {
        using (w.Element("Document"))
        {
            using (w.Element("RecordSet"))
            {
                w.Attribute("id", "1");
                using (w.Element("Master"))
                {
                    w.Attribute("name", masterTableName);
                    WriteTable(w, dataSet.Tables[masterTableName]);
                }
                foreach (DataTable table in dataSet.Tables)
                {
                    if (table.TableName == masterTableName) continue;
                    using (w.Element("Detail"))
                    {
                        w.Attribute("name", table.TableName);
                        WriteTable(w, table);
                    }
                }
            }
        }
    }
}

private static void WriteTable(XmlWriter w, DataTable table)
{
    foreach (DataRow row in table.Rows)
    {
        using (w.Element("Record"))
        {
            foreach (DataColumn col in table.Columns)
            {
                using (w.Element("Field"))
                {
                    w.Attribute("name", col.ColumnName);
                    w.Attribute("value", row[col].ToString());
                }
            }
        }
    }
}

相關的 Extension 及 class


{
    public static XNode Element(this XmlWriter w, string name)
    {
        return new XNode(name, w);
    }
    public static void Attribute(this XmlWriter w, string name, string value)
    {
        w.WriteAttributeString(name, value);
    }
}

public class XNode : IDisposable
{
    private readonly XmlWriter _w;
    public XNode(string name, XmlWriter w)
    {
        _w = w;
        _w.WriteStartElement(name);
    }
    public void Dispose()
    {
        _w.WriteEndElement();
    }
}