2013-08-03 31 views
2

這是我的計劃 -如何爲F#序列化獲得簡潔,清晰的XML輸出?

module Program 
open System 
open System.IO 
open System.Text 
open System.Xml 
open System.Xml.Serialization 
open System.Runtime.Serialization 
open System.Reflection 
open Microsoft.FSharp.Reflection 

let getUnionTypes<'a>() = 
    let nestedTypes = typedefof<'a>.GetNestedTypes(BindingFlags.Public ||| BindingFlags.NonPublic) 
    Array.filter FSharpType.IsUnion nestedTypes 

type Alpha = 
    { X : int * int 
     Y : Alpha option } 

type [<KnownType "GetTypes">] Beta = 
    | A of int * Alpha 
    | B of Beta option 
    | C of Map<int, Beta> 
    static member GetTypes() = getUnionTypes<Beta>() 

let [<EntryPoint>] main _ = 
    let alpha = { X = (0, 0); Y = Some { X = (1, 1); Y = None }} 
    let betaA = A (0, alpha) 
    let betaB = B (Some betaA) 
    let betaC = C (Map.singleton 0 betaB) 
    let sb = new StringBuilder() 
    let xmlSerializer = DataContractSerializer(typeof<Beta>); 
    xmlSerializer.WriteObject(new XmlTextWriter(new StringWriter(sb)), betaC) 
    let sr = sb.ToString() 
    printfn "%A" sr 
    0 

這裏的輸出 -

"<Program.Beta xmlns:i="http://www.w3.org/2001/XMLSchema-instance" i:type="Progr 
am.Beta.C" xmlns="http://schemas.datacontract.org/2004/07/"><item xmlns:d2p1="ht 
tp://schemas.datacontract.org/2004/07/Microsoft.FSharp.Collections"><d2p1:serial 
izedData xmlns:d3p1="http://schemas.datacontract.org/2004/07/System.Collections. 
Generic"><d3p1:KeyValuePairOfintProgram.BetalLTIrbuF><d3p1:key>0</d3p1:key><d3p1 
:value i:type="Program.Beta.B"><item xmlns:d6p1="http://schemas.datacontract.org 
/2004/07/Microsoft.FSharp.Core"><d6p1:value i:type="Program.Beta.A"><item1>0</it 
em1><item2><X_x0040_ xmlns:d9p1="http://schemas.datacontract.org/2004/07/System" 
><d9p1:m_Item1>0</d9p1:m_Item1><d9p1:m_Item2>0</d9p1:m_Item2></X_x0040_><Y_x0040 
_><d6p1:value><X_x0040_ xmlns:d11p1="http://schemas.datacontract.org/2004/07/Sys 
tem"><d11p1:m_Item1>1</d11p1:m_Item1><d11p1:m_Item2>1</d11p1:m_Item2></X_x0040_> 
<Y_x0040_ i:nil="true" /></d6p1:value></Y_x0040_></item2></d6p1:value></item></d 
3p1:value></d3p1:KeyValuePairOfintProgram.BetalLTIrbuF></d2p1:serializedData></i 
tem></Program.Beta>" 

我可能會做什麼簡單的事情,以改善這個XML輸出?我嘗試了各種屬性,但他們似乎都沒有幫助。請注意,我需要保持我的數據結構不可變,並且我希望避免編寫自己的序列化庫,或者如果可能的話,將依賴項添加到另一個自制的。它理想上應該是一個簡單的解決方案。

+0

不要使用可識別聯合 – mydogisbox

回答

0

你可以序列化之後漂亮地打印生成的字符串:

XDocument.Parse(sr).ToString() 

這個坐落在System.Xml.Linq集和命名空間。

+1

我認爲問題是,XML似乎包含大量unnecersary克魯夫特的,而不是缺乏漂亮的印刷 –

+0

如果所以,然後實現IXmlSerializable和手動序列化可能是最靈活的方法,並且使用模式匹配仍然會使其非常簡潔 –

+0

John是正確的;問題在於輸出中無用的冗餘文本。 –

1

我可以做些什麼簡單的事情來改善這種XML輸出?

.NET對串行化有很糟糕的支持,需要很長時間才能生成非常詳細的易碎消息。我強烈建議不要使用它。 (非免費)article about XML serialization in F#。我使用反射來解構F#類型的任意值,並將它們轉換爲XML並再次返回。性能遠遠優於內置的串行器,轉換結構比標稱值更好,因此您可以讀回到相同的類型定義(例如使用F#交互),但仍然比OCaml的內置序列化等競爭對手慢得多。隨着從文章的代碼你只是做:

> serialize betaC;; 
val it : string = 
    "<unionCase><name>C</name><map><keyValue><int>0</int><unionCase><name>B</name><unionCase><name>Some</name><unionCase><name>A</name><int>0</int><record><field><name>X</name><value><tuple><int>0</int><int>0</int></tuple></value></field><field><name>Y</name><value><unionCase><name>Some</name><record><field><name>X</name><value><tuple><int>1</int><int>1</int></tuple></value></field><field><name>Y</name><value><unionCase><name>None</name></unionCase></value></field></record></unionCase></value></field></record></unionCase></unionCase></unionCase></keyValue></map></unionCase>"