2012-07-16 77 views
0

我正在嘗試使用F#來執行我需要運行的其中一個實用程序作業。使用F#搜索元素,然後添加兄弟節點

從包含xml配置文件的目錄中,我想識別包含特定節點並查找匹配的所有文件,我想在同一個文件中插入兄弟節點。 我寫了一段代碼來識別所有文件,現在我有一系列文件,我想要迭代並搜索屬性並在必要時追加。

open System.Xml.Linq 

let byElementName elementToSearch = XName.Get(elementToSearch) 

let xmlDoc = XDocument.Load(@"C:\\Some.xml") 
xmlDoc.Descendants <| byElementName "Elem" 
|> Seq.collect(fun(riskElem) -> riskElem.Attributes <| byElementName "type") 
|> Seq.filter(fun(pvAttrib) -> pvAttrib.Value = "abc") 
|> Seq.map(fun(pvAttrib) -> pvAttrib.Parent) 
|> Seq.iter(printfn "%A") 

我想要做的是什麼,而不是最後的printf,添加類型爲"Elem"的另一個節點與type = "abc2"

<Product name="Node" inheritsfrom="Base"> 
     <SupportedElems> 
     <Elem type="abc" methodology="abcmeth" /> 
     <Elem type="def" methodology="defmeth" /> 
</SupportedElems> 
</Product> 

結果XML:

<Product name="Node" inheritsfrom="Base"> 
    <SupportedElems> 
    <Elem type="abc" methodology="abcmeth" /> 
    <Elem type="abc2" methodology="abcmeth" /> <!-- NEW ROW TO BE ADDED HERE --> 
    <Elem type="def" methodology="defmeth" /> 

+0

你忘記一些關閉標籤? xml文件格式不正確。 – pad 2012-07-16 11:59:02

+0

xml繼續使用類似的標籤..現在編輯問題 – Codex 2012-07-16 12:48:30

回答

3

在我看來複雜的LINQ to XML查詢是笨拙,使用XPath做得更好:

open System.Xml.Linq 
open System.Xml.XPath 

xmlDoc.XPathEvaluate("//Elem[@type='abc']") :?> _ 
|> Seq.cast<XElement> 
|> Seq.iter (fun el -> 
    el.AddAfterSelf(XElement.Parse(@"<Elem type=""abc2"" methodology=""abcmeth""/>"))) 

XML文檔後:

<Product name="Node" inheritsfrom="Base"> 
    <SupportedElems> 
    <Elem type="abc" methodology="abcmeth" /> 
    <Elem type="abc2" methodology="abcmeth" /> 
    <Elem type="def" methodology="defmeth" /> 
    </SupportedElems> 
</Product> 
+0

是的,這是有道理的。謝謝! – Codex 2012-07-16 16:34:53

1

您的功能正確地從文件中找到Elem元素,但它不會打印任何內容。您正在打印的elem.Value屬性是指元素的正文,在您的情況下爲空。如果您使用下面的輸入,然後它打印「一」和「二」:這樣

<Product name="Node" inheritsfrom="Base"> 
    <SupportedElems> 
    <Elem type="abc" methodology="abcmeth">one</Elem> 
    <Elem type="def" methodology="defmeth">two</Elem> 
    </SupportedElems> 
</Product> 

可以打印整個元素(而不只是身體):

let pvElement (configFile : string) = 
    let xmlDoc = XDocument.Parse configFile 
    xmlDoc.Descendants(byElementName "Elem") 
    |> Seq.iter (printfn "%A") 

如果你想選擇一個特定的元素(帶有一些指定的屬性),然後做一些事情,如果元素被發現,你可以使用Seq.tryPick函數,但這將是一個單獨的問題。

+0

感謝Tomas!斯里先生,這個問題一開始並不清楚。 printfn僅用於調試。我已經更新了它。希望它現在更清晰。 – Codex 2012-07-16 14:52:47

+0

@Codex - 我以爲你找到合適的元素有困難。關於添加 - 到目前爲止您嘗試了什麼?您是否找到'XElement'的Add方法(http://msdn.microsoft.com/zh-cn/library/system.xml.linq.xelement.add.aspx)?你想得到什麼樣的XML? – 2012-07-16 15:34:22

+0

我已經更新了結果XML。爲了添加節點,我試圖使用AddAfterSelf方法,但似乎沒有幫助。沒有編譯錯誤。 「讓InsertElement(elementToInsertAfter:XElement)= do elementToInsert |> elementToInsertAfter.AddAfterSelf」 – Codex 2012-07-16 15:50:23