2016-07-08 58 views
3

我試圖構建XML文檔的一小部分,以包含在最終文檔中。 當使用XDocument,我得到一個異常:我如何構建一個XML部分並保存到文件(本身不是一個有效的xml文檔)

「該操作將創建一個不正確的結構化文檔。」

因爲我的片段有多個「根」節點。

由於文件將被包含在一個更大的文檔中,我的基本元素將不會在最終文檔的根目錄中結束。

XDocument constsDocument = new XDocument(
    new XComment($" Consts section generated on {DateTime.Now} "), 
    new XComment($" First group of constants. "), 
    FirstTextConsts(MyFirstCollection), 
    new XComment($" Refrigerant constants. "), 
    SecondTextConsts(MySecondCollection) 
    ); 
// To avoid xml file starting with <?xml version="1.0" encoding="utf-8"?> use stringbuilder and StreamWriter. 
StringBuilder sb = new StringBuilder(); 
XmlWriterSettings xws = new XmlWriterSettings 
{ 
    OmitXmlDeclaration = true, 
    Indent = true 
}; 
using (XmlWriter xw = XmlWriter.Create(sb, xws)) 
{ 
    constsDocument.Save(xw); 
} 
System.IO.StreamWriter file = new System.IO.StreamWriter(_outputFileName); 
file.WriteLine(sb.ToString()); 
file.Close(); 

EDIT 1: 兩種方法創建的文檔中調用(在主要):

private static IEnumerable<XElement> FirstTextConsts(IEnumerable<MyClass> collection) 
{ 
    return collection.Select(r => new XElement("const", 
      new XAttribute("name", $"IDENTIFIER_{r.Id}"), 
      new XAttribute("translatable", "false"), 
      new XElement("text", 
       new XAttribute("lang","en"), r.Name)));    
} 

private static IEnumerable<XElement> SecondTextConsts(IEnumerable<MyClass> collection) 
{ 
    foreach (var obj in collection) 
    { 
     if (obj.SomeSelector) 
      yield return new XElement("const", 
       new XAttribute("name", $"IDENTIFIER_{r.Id}"), 
       new XAttribute("translatable", "false"), 
       new XElement("text", 
        new XAttribute("lang","en"), r.Name)));    
     if (obj.SomeOtherSelector) 
      yield return new XElement("const", 
       new XAttribute("name", $"IDENTIFIER_{r.Id}"), 
       new XAttribute("translatable", "true") 
       );    
    } 
} 

編輯2: 正如我確實需要的XDocument的靈活性,以建立多級XML document helper方法返回不同級別的IEnumerable,我決定添加一個僞元素並在寫入文件之前再次刪除它:

XDocument constsDocument = new XDocument(
    new XElement("root", 
     new XComment($" Consts section generated on {DateTime.Now} "), 
     new XComment($" First group of constants. "), 
     FirstTextConsts(MyFirstCollection), 
     new XComment($" Refrigerant constants. "), 
     SecondTextConsts(MySecondCollection) 
     ) 
    ); 

之前寫入文件我剝元素:

file.WriteLine(sb.ToString().Replace("<root>" + Environment.NewLine, "").Replace(Environment.NewLine + "</root>", "")); 

回答

1

你可以聲明你想XML是距離的XDocument片段和開關的XMLDocument:

XmlDocument constDocument = new XmlDocument(); 
constDocument.CreateComment(" Consts section generated on {DateTime.Now} "); 
constDocument.CreateComment(" First group of constants. "); 
FirstTextConsts(MyFirstCollection); // Need to be adapted 
constDocument.CreateComment(" Refrigerant constants. "); 
SecondTextConsts(MySecondCollection); // Need to be adapted 
XmlDocumentFragment fragDocument = constDocument.CreateDocumentFragment(); 
fragDocument.InnerXml = "<const>fragment</const><const>fragment2</const>"; // Need to be adapted 

StringBuilder sb = new StringBuilder(); 
XmlWriterSettings xws = new XmlWriterSettings 
{ 
    ConformanceLevel = ConformanceLevel.Fragment, 
    OmitXmlDeclaration = true, 
    Indent = true 
}; 
using (XmlWriter xw = XmlWriter.Create(sb, xws)) 
{ 
    fragDocument.WriteContentTo(xw); 
} 
System.IO.StreamWriter file = new System.IO.StreamWriter(_outputFileName); 
file.WriteLine(sb.ToString()); 
file.Close(); 

或添加aritificial根元素:

"<aritificialroot>" + fragment + "</aritificialroot>" 
3

您不能創建無效的XDocument(由於多個「根」節點)。因此,您需要創建一個節點列表,並將其寫入文檔片段。

var constsDocument = new List<XNode> { 
      new XComment($" Consts section generated on {DateTime.Now} "), 
      new XComment($" First group of constants. "), 
      new XElement("example"), 
      new XComment($" Refrigerant constants. "), 
      new XElement("another") 
}; 
// To avoid xml file starting with <?xml version="1.0" encoding="utf-8"?> use stringbuilder and StreamWriter. 
StringBuilder sb = new StringBuilder(); 
XmlWriterSettings xws = new XmlWriterSettings 
{ 
    OmitXmlDeclaration = true, 
    Indent = true, 
    ConformanceLevel = ConformanceLevel.Fragment 
}; 
using (XmlWriter xw = XmlWriter.Create(sb, xws)) 
{ 
    foreach (var element in constsDocument) 
    { 
     element.WriteTo(xw); 
    } 
} 
System.IO.StreamWriter file = new System.IO.StreamWriter(_outputPath); 
file.WriteLine(sb.ToString()); 
file.Close(); 

編輯:使用它返回一個IEnumerable<XElement>List對象初始化裏面的方法,你就必須稍微改變的定義和添加其他項目的方式:

var constsDocument = new List<IEnumerable<XNode>> { 
    new [] { new XComment($" Consts section generated on {DateTime.Now} ") }, 
    new [] { new XComment($" First group of constants. ") }, 
    FirstTextConsts(MyFirstCollection), 
    new [] { new XComment($" Refrigerant constants. ") }, 
    SecondTextConsts(MySecondCollection) 
); 

...

foreach (var element in constsDocument.SelectMany(n => n)) 
+0

我已經編輯我的問題來說明這兩種方法是所謂杜裏創建文檔。他們不會在對象初始值設定器中工作,如你所建議的那樣? – TheRoadrunner

+0

@TheRoadrunner我剛剛更新了我的答案,提供了一種可能的解決方案,使用兩個返回多個'XElement'實例的方法。 –

+0

非常感謝您的更新。它按照你的建議工作。 – TheRoadrunner

相關問題