我正在尝试使用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 :(得分: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>
答案 1 :(得分:1)
您的函数正确地从文件中找到Elem
元素,但它不会打印任何内容。您正在打印的elem.Value
属性是指元素的 body ,在您的情况下为空。如果您使用以下输入,则打印“one”和“two”:
<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
函数,但那是一个单独的问题。