Reputation: 955
Assume I have this XML
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" mergefield="blah">
<filter blah="rrr"></filter>
<filter blah="qqq"></filter>
<filter blah="www"></filter>
</hibernate-mapping>
Each time targetElement
should be assigned if its corresponding attribute name is found in sourceElement
namespace Test
{
class Program
{
static void Main(string[] args)
{
var path = (@"PATHFORXML");
XElement target = XElement.Load(path);
XElement source = XElement.Load(path);
foreach (var sourceElement in source.Elements())
{
XElement targetElement = target.Elements().SingleOrDefault(
t =>
String.Equals(
(string)t.Attribute(GetMergeAttr(target)),
(string)sourceElement.Attribute(GetMergeAttr(source)),
StringComparison.InvariantCultureIgnoreCase)
);
}
Console.ReadLine();
}
private static string GetMergeAttr(XElement element)
{
return (string)element.Attribute("mergefield");
}
}
}
PROBLEM
Now I have a situation where mergefield
can be either "blah"
or "blahblah"
. So I want above code to work same way for this XML:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" mergefield="blah,blahblah">
<filter blah="rrr"></filter>
<filter blahblah="qqq"></filter>
<filter blahblah="www"></filter>
</hibernate-mapping>
Aka, either of mergefields
should work
My attempts are those. GetMergeAttr
should become this:
private static string[] GetMergeAttr(XElement element)
{
var f = ((string)element.Attribute("mergefield")).Split(',');
return f;
}
and I can't finish query part
XElement targetElement = target.Elements().SingleOrDefault(
t =>
String.Equals(
(string)t.Attribute(GetMergeAttr(target).SingleOrDefault(u=> ?????????)),
(string)sourceElement.Attribute(GetMergeAttr(source).SingleOrDefault(u => ?????????))
)
);
This works, but what if I have more than 3 mergefield values (I need to update this query to accept any number of mergefields, not just 2):
XElement targetElement = target.Elements().SingleOrDefault(
t =>
String.Equals(
(string)t.Attribute(GetMergeAttr(target).Last())?? (string)t.Attribute(GetMergeAttr(target).First()),
(string)sourceElement.Attribute(GetMergeAttr(source).Last()) ?? (string)sourceElement.Attribute(GetMergeAttr(source).First())
)
);
Upvotes: 1
Views: 116
Reputation: 18155
Update based on comments.
I assume following is what you require
XElement target = XElement.Parse(txml);
XElement source = XElement.Parse(sxml);
var targetMergeAttrs = GetMergeAttr(target);
var sourceMergeAttrs = GetMergeAttr(source);
foreach (var sourceElement in source.Elements())
{
foreach(var mergeField in sourceMergeAttrs)
{
if(sourceElement.Attributes().Any(x=>x.Name.LocalName.Equals(mergeField)) &&
target.Elements()
.Any(x=>x.Attributes()
.Where(c=>c.Name.LocalName == mergeField
&& targetMergeAttrs.Contains(mergeField)
&& c.Value == (string)sourceElement.Attribute(mergeField)).Any()
))
{
XElement targetElement = target.Elements()
.FirstOrDefault(x=>x.Attributes()
.Where(c=>c.Name.LocalName == mergeField
&& targetMergeAttrs.Contains(mergeField)
&& c.Value == (string)sourceElement.Attribute(mergeField)).Any()
);
// Do work with targetElement
break;
}
}
}
Upvotes: 1
Reputation: 1425
I am not sure what you want to achieve but does this code behave as expected?
using System;
using System.Linq;
using System.Xml.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var path = (@"PATH");
XElement target = XElement.Load(path);
XElement source = XElement.Load(path);
var mergefields = GetMergeAttr(target);
foreach (var sourceElement in source.Elements())
{
var targetElements = from mergefield in mergefields
select target.Elements().SingleOrDefault(t =>
{
if (t.Attribute(mergefield) == null || sourceElement.Attribute(mergefield) == null)
{
return false;
}
return String.Equals(
t.Attribute(mergefield).Value,
sourceElement.Attribute(mergefield).Value,
StringComparison.InvariantCultureIgnoreCase);
}
);
foreach (var element in targetElements)
{
Console.WriteLine(element);
}
}
Console.ReadLine();
}
private static string[] GetMergeAttr(XElement element)
{
string mergefield = (string)element.Attribute("mergefield");
return mergefield.Split(',');
}
}
}
Upvotes: 0