I have the following source as XML:
<?xml version="1.0"?>
<report>
    <feature tag="Config"/>
    <feature tag="Runtime">
        <feature tag="Metadata">
            <property name="date" value="16.01.2025"/>
            <property name="time" value="09:31:34"/>
        </feature>
        <feature tag="Templates">
            <feature tag="Template">
                <property name="username" value="myself"/>
                <property name="password" value="something"/>
                <feature tag="Data sources">
                    <feature tag="Source">
                        <property name="name" value="modules"/>
                        <property name="driver" value="eval"/>
                    </feature>
                    <feature tag="Source">
                        <property name="name" value="Artifact"/>
                        <property name="driver" value="eval"/>
                    </feature>
                    <feature tag="Source">
                        <property name="name" value="Comments"/>
                        <property name="driver" value="eval"/>
                        </feature>
                    </feature>
                </feature>
            </feature>
        </feature>
    </feature>
</report>
I want to modify the value of the driver property (below the feature tag Source), but only if the value of the name property (below the feature tag Source) equals the word "modules".
I tried to use the following function only to extract the feature tags Source. I think it is possible to modify the properties in the way I want in one LINQ command, but I don't know how to formulate this if construct in XPath.
Private Function ModifyXml(ByVal xml As String) As Boolean
     Try
         Dim xdoc As New XDocument
         xdoc = XDocument.Parse(xml)
         Dim query As String = "/report/feature[@tag='Runtime']/feature[@tag='Templates']/feature[@tag='Template']/feature[@tag='Data sources']/feature[@tag='Source']"
         xdoc.XPathSelectElements(query).ToList()
         xdoc.Save("c:\temp\myFile.xml")
         Return True
     Catch ex As Exception
         Return False
     End Try
 End Function
The result should look like this:
I need a driver name in the properties as value. This driver name depends on the value of the name properties.
<?xml version="1.0"?>
<report>
    <feature tag="Config"/>
    <feature tag="Runtime">
        <feature tag="Metadata">
            <property name="date" value="16.01.2025"/>
            <property name="time" value="09:31:34"/>
        </feature>
        <feature tag="Templates">
            <feature tag="Template">
                <property name="username" value="myself"/>
                <property name="password" value="something"/>
                <feature tag="Data sources">
                    <feature tag="Source">
                        <property name="name" value="modules"/>
                        <property name="driver" value="somedriver1"/>
                    </feature>
                    <feature tag="Source">
                        <property name="name" value="Artifact"/>
                        <property name="driver" value="somedriver2"/>
                    </feature>
                    <feature tag="Source">
                        <property name="name" value="Comments"/>
                        <property name="driver" value="somedriver3"/>
                        </feature>
                    </feature>
                </feature>
            </feature>
        </feature>
    </feature>
</report>
I have the following source as XML:
<?xml version="1.0"?>
<report>
    <feature tag="Config"/>
    <feature tag="Runtime">
        <feature tag="Metadata">
            <property name="date" value="16.01.2025"/>
            <property name="time" value="09:31:34"/>
        </feature>
        <feature tag="Templates">
            <feature tag="Template">
                <property name="username" value="myself"/>
                <property name="password" value="something"/>
                <feature tag="Data sources">
                    <feature tag="Source">
                        <property name="name" value="modules"/>
                        <property name="driver" value="eval"/>
                    </feature>
                    <feature tag="Source">
                        <property name="name" value="Artifact"/>
                        <property name="driver" value="eval"/>
                    </feature>
                    <feature tag="Source">
                        <property name="name" value="Comments"/>
                        <property name="driver" value="eval"/>
                        </feature>
                    </feature>
                </feature>
            </feature>
        </feature>
    </feature>
</report>
I want to modify the value of the driver property (below the feature tag Source), but only if the value of the name property (below the feature tag Source) equals the word "modules".
I tried to use the following function only to extract the feature tags Source. I think it is possible to modify the properties in the way I want in one LINQ command, but I don't know how to formulate this if construct in XPath.
Private Function ModifyXml(ByVal xml As String) As Boolean
     Try
         Dim xdoc As New XDocument
         xdoc = XDocument.Parse(xml)
         Dim query As String = "/report/feature[@tag='Runtime']/feature[@tag='Templates']/feature[@tag='Template']/feature[@tag='Data sources']/feature[@tag='Source']"
         xdoc.XPathSelectElements(query).ToList()
         xdoc.Save("c:\temp\myFile.xml")
         Return True
     Catch ex As Exception
         Return False
     End Try
 End Function
The result should look like this:
I need a driver name in the properties as value. This driver name depends on the value of the name properties.
<?xml version="1.0"?>
<report>
    <feature tag="Config"/>
    <feature tag="Runtime">
        <feature tag="Metadata">
            <property name="date" value="16.01.2025"/>
            <property name="time" value="09:31:34"/>
        </feature>
        <feature tag="Templates">
            <feature tag="Template">
                <property name="username" value="myself"/>
                <property name="password" value="something"/>
                <feature tag="Data sources">
                    <feature tag="Source">
                        <property name="name" value="modules"/>
                        <property name="driver" value="somedriver1"/>
                    </feature>
                    <feature tag="Source">
                        <property name="name" value="Artifact"/>
                        <property name="driver" value="somedriver2"/>
                    </feature>
                    <feature tag="Source">
                        <property name="name" value="Comments"/>
                        <property name="driver" value="somedriver3"/>
                        </feature>
                    </feature>
                </feature>
            </feature>
        </feature>
    </feature>
</report>
You could use a simple xslt to do the job:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 
  <xsl:output method="xml" indent="yes"/>
  <!-- Identity template to copy the rest of the XML as is -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  <!-- 
    A template match on with this xpath for the correct attribute to change:
    feature[property/@value='modules']/property[@name='driver']/@value
  -->
  <xsl:template match="feature[property/@value='modules']/property[@name='driver']/@value">
    <xsl:attribute name="value">somedriver1</xsl:attribute>
  </xsl:template> 
  <!-- 
    A template match on with this xpath for the correct attribute to change:
    feature[property/@value='Artifact']/property[@name='driver']/@value
  -->
  <xsl:template match="feature[property/@value='Artifact']/property[@name='driver']/@value">
    <xsl:attribute name="value">somedriver2</xsl:attribute>
  </xsl:template>
  <!-- 
    A template match on with this xpath for the correct attribute to change:
    feature[property/@value='Comments']/property[@name='driver']/@value
  -->
  <xsl:template match="feature[property/@value='Comments']/property[@name='driver']/@value">
    <xsl:attribute name="value">somedriver3</xsl:attribute>
  </xsl:template>
</xsl:stylesheet>
XPath queries, it doesn't modify. As the name suggests, XPathSelectElements returns the nodes you want. You'll have to process each one of them and modify the correct child elements. The unconventional XML schema makes this harder than needed -Templates,Source, Comments etc should all be elements, not values in a generic attribute. No flexibility is gained by the current format.
LINQ is also a query, not a modification language, it doesn't modify. No matter what language you use you'll have to iterate over the feature elements they produce and for each one, retrieve the name or driver children and modify their value attribute.
Comment from Panagiotis Kanavos
Using this data
    Dim docXE As XElement
    'test data
    docXE = <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 tag="Metadata">
                        <property name="date" value="16.01.2025"/>
                        <property name="time" value="09:31:34"/>
                    </feature>
                    <feature tag="Templates">
                        <feature tag="Template">
                            <property name="username" value="myself"/>
                            <property name="password" value="something"/>
                            <feature tag="Data sources">
                                <feature tag="Source">
                                    <property name="name" value="modules"/>
                                    <property name="driver" value="eval"/>
                                </feature>
                                <feature tag="Source">
                                    <property name="name" value="Artifact"/>
                                    <property name="driver" value="eval"/>
                                </feature>
                                <feature tag="Source">
                                    <property name="name" value="Comments"/>
                                    <property name="driver" value="eval"/>
                                </feature>
                            </feature>
                        </feature>
                    </feature>
                </feature>
            </report>
Try this code.
    Dim selMod As List(Of XElement)
    selMod = (From el In docXE...<feature>
                Where el.@tag = "Source" AndAlso
                 el.<property>.@value = "modules"
                     From src In el.<property>
                        Where src.@name = "driver"
                        Select src).ToList
    For Each el As XElement In selMod
        el.@name = "FOODriver"
    Next


XPathSelectElementsreturns the nodes you want. You'll have to process each one of them and modify the correct child elements. The unconventional XML schema makes this harder than needed -Templates,Source,Commentsetc should all be elements, not values in a generic attribute. No flexibility is gained by the current format – Panagiotis Kanavos Commented Jan 16 at 11:55featureelements they produce and for each one, retrieve thenameordriverchildren and modify theirvalueattribute. – Panagiotis Kanavos Commented Jan 16 at 12:02