Reputation: 1
Assuming that I have following XML:
<?xml version="1.0" encoding="UTF-8" ?>
<exchange xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://download.autodesk.com/us/navisworks/schemas/nw-exchange-12.0.xsd" units="ft" filename="" filepath="">
<batchtest name="3636" internal_name="3636" units="ft">
<clashtests>
<clashtest name="Ducts VS Ducts" test_type="hard" status="new" tolerance="0.0000000000" merge_composites="0">
<linkage mode="none"/>
<left>
<clashselection selfintersect="0" primtypes="1">
<locator>/</locator>
</clashselection>
</left>
<right>
<clashselection selfintersect="0" primtypes="1">
<locator>/</locator>
</clashselection>
</right>
<rules/>
</clashtest>
<clashtest name="Ducts VS Cable Trays" test_type="hard" status="new" tolerance="0.0000000000" merge_composites="0">
<linkage mode="none"/>
<left>
<clashselection selfintersect="0" primtypes="1">
<locator>/</locator>
</clashselection>
</left>
<right>
<clashselection selfintersect="0" primtypes="1">
<locator>/</locator>
</clashselection>
</right>
<rules/>
</clashtest>
</batchtest>
</exchange>
I want to do like this image using C# in Visual Studio
I want to change the value of locator node to depend on the value of clash test node as shown in the image.
Upvotes: 0
Views: 414
Reputation: 22187
XSLT has so called Identity Transformation pattern.
Useful link: XSL Identity Transforms
The XSLT below will copy the entire input XML as-is with the exception of the locator element. The moment the locator element is found, it will be replaced with the new desired value.
XSLT functions substring-before()
and substring-after()
easily retrieving a needed part of the name attribute value.
All you have to do is just to call XSLT transformation from your c# code.
XSLT
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml" encoding="utf-8"/>
<!-- IdentityTransform -->
<xsl:template match="/ | @* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="locator[parent::clashselection/parent::left]">
<locator>
<xsl:value-of select="substring-before(ancestor::clashtest/@name, ' VS')"/>
</locator>
</xsl:template>
<xsl:template match="locator[parent::clashselection/parent::right]">
<locator>
<xsl:value-of select="substring-after(ancestor::clashtest/@name, 'VS ')"/>
</locator>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Reputation: 14231
var xml = XElement.Load("test.xml");
var clashtests = xml.Element("batchtest").Element("clashtests").Elements("clashtest");
foreach (var clashtest in clashtests)
{
string name = clashtest.Attribute("name").Value;
var values = name.Split(new[] { " VS " }, StringSplitOptions.None);
var left = clashtest.Element("left").Element("clashselection").Element("locator");
left.Value = values[0];
var right = clashtest.Element("right").Element("clashselection").Element("locator");
right.Value = values[1];
}
Console.WriteLine(xml);
Specifying the full path: Element(...).Element(...)
is faster than Descendants
. It can be critical on large documents.
Upvotes: 0
Reputation: 34429
Use xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
foreach (XElement clashtest in doc.Descendants("clashtest"))
{
string name = (string)clashtest.Attribute("name");
string pattern = "(?'name1'.*)VS(?'name2'.*)";
Match match = Regex.Match(name, pattern);
string name1 = match.Groups["name1"].Value.Trim();
string name2 = match.Groups["name2"].Value.Trim();
List<XElement> locators = clashtest.Descendants("locator").ToList();
locators[0].SetValue(name1);
locators[1].SetValue(name2);
}
}
}
}
Upvotes: 0