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>