As source I have a XML document with the following content:
<?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>
If the value of the tag attribute within the feature element Target is not equal Word, I want to remove the complete feature element Target in order to look like the following result:
<?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>
Therefore, I prepared the following vb.net function:
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
The problem is, that my code removes all Target feature elements, so that the Output feature element is empty, as you can see in the result:
<?xml version="1.0" encoding="utf-8"?>
<report>
<feature tag="Config"></feature>
<feature tag="Runtime">
<feature tag="Output" />
</feature>
</report>
I found no solution with help of LINQ to remove every Target feature element, except that one, that holds the string "Word" as attribute value.
Here is a working solution implemented in both c# and VB.NET.
c#
void Main()
{
const string inputXML = @"e:\Temp\input.xml";
const string outputXML = @"e:\Temp\output.xml";
XDocument xdoc = XDocument.Load(inputXML);
xdoc.XPathSelectElements("/report/feature[@tag='Runtime']/feature[@tag='Output']/feature[not(property/@value='Word')]")
.ToList()
.ForEach(x => x.Remove());
xdoc.Save(outputXML);
}
VB.NET
Sub Main
Const inputXML As String = "e:\Temp\input.xml"
Const outputXML As String = "e:\Temp\output.xml"
Dim xdoc As XDocument = XDocument.Load(inputXML)
xdoc.XPathSelectElements("/report/feature[@tag='Runtime']/feature[@tag='Output']/feature[not(property/@value='Word')]") _
.ToList().ForEach(Sub(x) x.Remove())
xdoc.Save(outputXML)
End Sub