【问题标题】:Using F# to search for an element and then adding sibling node使用 F# 搜索元素,然后添加兄弟节点
【发布时间】:2012-07-15 06:13:39
【问题描述】:

我正在尝试将 F# 用于我需要运行的实用程序之一。

从包含 xml 配置文件的目录中,我想识别包含特定节点的所有文件,并且在找到匹配项时,我想在同一个文件中插入一个兄弟节点。 我已经编写了 sn-p 来识别所有文件,现在我有一系列文件,我想对其进行迭代并搜索属性并在必要时追加。

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" />

【问题讨论】:

  • 您忘记了一些结束标签吗? xml 文件格式不正确。
  • xml 继续使用类似的标签。现在将编辑问题

标签: f# xml-parsing linq-to-xml


【解决方案1】:

在我看来,复杂的 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>

【讨论】:

  • 是的,这是有道理的。谢谢!
【解决方案2】:

您的函数正确地从文件中找到Elem 元素,但它不打印任何内容。您正在打印的 elem.Value 属性指的是元素的 body,在您的情况下它是空的。如果您使用以下输入,则它会打印“一”和“二”:

<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 函数,但这将是一个单独的问题。

【讨论】:

  • 谢谢托马斯!对不起,这个问题一开始并不清楚。 printfn 仅用于调试。我已经进一步更新了它。希望现在更清楚了。
  • @Codex - 我认为您在找到正确的元素时遇到了麻烦。关于添加-到目前为止您尝试了什么?找到XElementmsdn.microsoft.com/en-us/library/…)的Add方法了吗?作为结果,您希望得到什么 XML?
  • 我已经更新了结果 XML。为了添加节点,我尝试使用 AddAfterSelf 方法,但这似乎没有帮助。也没有编译错误。 "让 InsertElement (elementToInsertAfter:XElement) = do elementToInsert |> elementToInsertAfter.AddAfterSelf"
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-16
  • 2022-01-17
  • 2014-02-05
相关资源
最近更新 更多