F#使用XML类型提供程序修改XML

6
我需要处理一些XML文档。它们的结构相当复杂(即有许多节点),但处理只涉及更改少数节点的值并将文件保存为不同的名称。我正在寻找一种方法,在不必通过显式实例化所有类型和传递所有未更改的值的情况下来完成此操作,而是通过从输入中复制它们来完成。如果类型提供程序自动生成的类型是记录类型,那么我可以通过 let output = { input with changedNode = myNewValue } 来创建输出,但使用类型提供程序,我必须这样做: let output = MyXml.MyRoot(input.UnchangedNode1, input.UnchangedNode2, myNewValue, input.UnchangedNode3, ...) 。我的更改值在一些嵌套节点中,这进一步增加了传递参数的复杂程度。

3
我建议不要使用 Xml 类型提供程序,而是使用一些 XSLT。可能需要更多信息才能更好地理解。对我来说,这听起来像某种条件搜索和替换,但当然也可能只是我的想法。 - Helge Rene Urholm
1
镜头!你想要镜头! - Mark Seemann
@MarkSeemann 是的和不是的,但主要是是的。而且更多的是不是的。所以也许吧。;-) 在这种情况下,如果类型提供程序允许它,那实际上会是一件“好”事情,正如Tomas“作弊”解释的那样。直到“编写这个新的XML”,类型提供程序仍然做不到... - Helge Rene Urholm
1
在这个意义上,@MarkSeemann 是正确的方向,并回答了我未提出的问题,提供了一个函数式编程惯用语的建议。 - user2916547
@user2916547 XSLT(可被函数式编程影响)...奇怪的是;-) - Helge Rene Urholm
显示剩余2条评论
1个回答

10

F#数据类型提供程序主要设计用于读取数据时轻松访问,因此它们在写入数据方面没有很好的适用性(部分原因是底层JSON表示与底层XML表示非常不同)。

对于XML,类型提供程序只是包装标准的XElement类型,这些类型恰好是可变的。这意味着您实际上可以使用提供的类型导航到元素,然后使用底层的LINQ to XML来修改值。例如:

type X = XmlProvider<"<foos><foo a=\"1\" /><foo a=\"2\" /></foos>">

// Change the 'a' attribute of all 'foo' nodes to 1234
let doc = X.GetSample()
for f in doc.Foos do
  f.XElement.SetAttributeValue(XName.Get "a", 1234)

// Prints the modified document    
doc.ToString()

可能并不完美 - 有时候,你需要改变父元素(比如这里,提供的f.A属性是不可变的),但它可能会起到作用。我不知道这是否是解决问题的最佳方式,或者像XSLT这样的东西是否更容易 - 这可能取决于具体的转换。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接