如何用LINQ移除XML中属性值非Word的Target类型feature元素?
问题:移除XML中不符合条件的Target元素
原始XML文档
<?xml version="1.0"?> <report> <feature tag="Config"/> <feature tag="Runtime"> <feature tag="Output"> <feature tag="Target"> <property name="type" value="Html"/> <property name="driver" value="Telelogic.Html.Driver"/> </feature> <feature tag="Target"> <property name="type" value="Word"/> <property name="driver" value="Telelogic.Word.Driver"/> </feature> <feature tag="Target"> <property name="type" value="PDF"/> <property name="driver" value="Telelogic.Pdf.Driver"/> </feature> </feature> </feature> </report>
期望处理结果
只保留type属性值为Word的Target元素,其余不符合条件的全部移除:
<?xml version="1.0"?> <report> <feature tag="Config"/> <feature tag="Runtime"> <feature tag="Output"> <feature tag="Target"> <property name="type" value="Word"/> <property name="driver" value="Telelogic.Word.Driver"/> </feature> </feature> </feature> </report>
原代码及问题
原VB.NET代码尝试实现需求,但错误地移除了所有Target元素,导致Output节点为空:
Public Function removeElements(ByVal source As String) As Boolean Try Dim doc As New XDocument Dim output As String = "/report/feature[@tag='Runtime']/feature[@tag='Output']" Dim propertyType As String = "/report/feature[@tag='Runtime']/feature[@tag='Output']/feature[@tag='Target']/property[@name='type']" Dim path As String = "c:\temp\mySource.xml" doc = XDocument.Parse(source) doc.XPathSelectElements(output).Elements _ .Where(Function(x) x.XPathSelectElement(propertyType).Attribute("value").Value <> "Word").Remove doc.Save(path) Return True Catch ex As Exception Return False End Try End Function
问题根源:propertyType用了绝对XPath路径,导致每个Target元素都会去匹配整个文档中第一个type属性(值为Html),所有Target都被判定为不符合条件并删除。
修正后的解决方案
方法1:使用相对XPath路径
把propertyType改成相对当前Target元素的路径,直接查找子节点的property:
Public Function removeElements(ByVal source As String) As Boolean Try Dim doc As New XDocument Dim path As String = "c:\temp\mySource.xml" doc = XDocument.Parse(source) ' 直接定位到所有Target元素 doc.XPathSelectElements("/report/feature[@tag='Runtime']/feature[@tag='Output']/feature[@tag='Target']") _ .Where(Function(target) ' 用相对路径找当前Target下的type属性 target.XPathSelectElement("property[@name='type']").Attribute("value").Value <> "Word" ).Remove() doc.Save(path) Return True Catch ex As Exception Return False End Try End Function
方法2:纯LINQ to XML写法(更直观)
完全用LINQ语法筛选元素,避免XPath路径错误:
Public Function removeElements(ByVal source As String) As Boolean Try Dim doc As XDocument = XDocument.Parse(source) Dim path As String = "c:\temp\mySource.xml" ' 找到Output节点下的所有Target元素 Dim targetElements = doc.Descendants("feature") _ .Where(Function(f) f.Attribute("tag")?.Value = "Output") _ .Elements("feature") _ .Where(Function(t) t.Attribute("tag")?.Value = "Target") ' 筛选出type不等于Word的元素并删除 targetElements.Where(Function(t) t.Elements("property") _ .Any(Function(p) p.Attribute("name")?.Value = "type" AndAlso p.Attribute("value")?.Value <> "Word") ).Remove() doc.Save(path) Return True Catch ex As Exception Return False End Try End Function
两种方法都能精准筛选出需要删除的Target元素,只保留type=Word的节点。
内容的提问来源于stack exchange,提问作者Manfred Singer
相关产品推荐
相关产品推荐

