Dear Greg,
I used your code and found it worked excellently! Now I need to step it up a bit and have got problems:
<groupA>
<rowA>
<fieldA1>
<groupB>
<rowB>
<fieldB2>
</rowB>
</groupB>
<groupC>
<rowC>
<fieldC2>
</rowC>
</groupC>
</rowA>
</groupA>
In the above (where there are multiple <rowA>'s, <rowB>'s and <rowC>'s, I am trying to copy the value in <fieldB2> to the value in <fieldC2>. The context of the "Copy" button is <rowB>, so it should be possible to copy to the new context of <rowC> whilst keeping the context of <rowA>.
The problem is that the context of <rowA> is inaccessible. Here is the original code (non-nested) that works:
public void elnCopyToProposed_Clicked(object sender, ClickedEventArgs e)
{
// Create temp copy object
XmlDocument doc = new XmlDocument();
XmlNode group = null;
XmlNode node = null;
// Check parent node exists
if (MainDataSource.CreateNavigator().SelectSingleNode("/my:Case/my:Facilities/my:Proposed/my:Loans",
this.NamespaceManager) == null)
{
group = doc.CreateElement("my:Loans", NamespaceManager.LookupNamespace("my"));
XmlNode nodeOrphan = doc.CreateElement("my:Loan", NamespaceManager.LookupNamespace("my"));
node = group.AppendChild(nodeOrphan);
}
else
{
node = doc.CreateElement("my:Loan", NamespaceManager.LookupNamespace("my"));
}
{
// Create and add fields
XmlNode fieldOrphan = doc.CreateElement("my:lnBalance", NamespaceManager.LookupNamespace("my"));
XmlNode field = node.AppendChild(fieldOrphan);
field.InnerXml = e.Source.SelectSingleNode("my:elnBalance", this.NamespaceManager).InnerXml;
fieldOrphan = doc.CreateElement("my:lnLoanType", NamespaceManager.LookupNamespace("my"));
field = node.AppendChild(fieldOrphan);
field.InnerXml = e.Source.SelectSingleNode("my:elnLoanType", this.NamespaceManager).InnerXml;
fieldOrphan = doc.CreateElement("my:lnTermRemaining", NamespaceManager.LookupNamespace("my"));
field = node.AppendChild(fieldOrphan);
field.InnerXml = e.Source.SelectSingleNode("my:elnOriginalTerm", this.NamespaceManager).InnerXml;
}
// Add the doc to the main data
if (group != null)
{
doc.AppendChild(group);
MainDataSource.CreateNavigator().SelectSingleNode("/my:Case/my:Facilities/my:Proposed",
this.NamespaceManager).AppendChild(doc.DocumentElement.CreateNavigator());
}
else
{
doc.AppendChild(node);
MainDataSource.CreateNavigator().SelectSingleNode("/my:Case/my:Facilities/my:Proposed/my:Loans",
this.NamespaceManager).AppendChild(doc.DocumentElement.CreateNavigator());
}
}
And the (nested) code that doesn't:
public void oelnCopyToProposed_Clicked(object sender, ClickedEventArgs e)
{
// Create temp copy object
XmlDocument doc = new XmlDocument();
XmlNode group = null;
XmlNode node = null;
// Check parent node exists /my:Case/my:OtherFacilities/my:oFacilities/my:oExisting/my:oeLoans
if (e.Source.CreateNavigator().SelectSingleNode("ancestor::my:oFacilities/my:oProposed/my:oLoans",
this.NamespaceManager) == null)
{
group = doc.CreateElement("my:oeLoans", NamespaceManager.LookupNamespace("my"));
XmlNode nodeOrphan = doc.CreateElement("my:oeLoan", NamespaceManager.LookupNamespace("my"));
node = group.AppendChild(nodeOrphan);
}
else
{
node = doc.CreateElement("my:oeLoan", NamespaceManager.LookupNamespace("my"));
}
{
// Create and add fields
XmlNode fieldOrphan = doc.CreateElement("my:olnBalance", NamespaceManager.LookupNamespace("my"));
XmlNode field = node.AppendChild(fieldOrphan);
field.InnerXml = e.Source.SelectSingleNode("my:oelnBalance", this.NamespaceManager).InnerXml;
fieldOrphan = doc.CreateElement("my:olnLoanType", NamespaceManager.LookupNamespace("my"));
field = node.AppendChild(fieldOrphan);
field.InnerXml = e.Source.SelectSingleNode("my:oelnLoanType", this.NamespaceManager).InnerXml;
fieldOrphan = doc.CreateElement("my:olnTermRemaining", NamespaceManager.LookupNamespace("my"));
field = node.AppendChild(fieldOrphan);
field.InnerXml = e.Source.SelectSingleNode("my:oelnOriginalTerm", this.NamespaceManager).InnerXml;
}
// Add the doc to the main data
if (group != null)
{
doc.AppendChild(group);
e.Source.CreateNavigator().SelectSingleNode("ancestor::my:oFacilities/my:oProposed",
this.NamespaceManager).AppendChild(doc.DocumentElement.CreateNavigator());
}
else
{
doc.AppendChild(node);
e.Source.CreateNavigator().SelectSingleNode("ancestor::my:oFacilities/my:oProposed/my:oLoans",
this.NamespaceManager).AppendChild(doc.DocumentElement.CreateNavigator());
}
}
Note that I am also checking that the target group node exists... <oFacilities> is structurally equivalent to <rowA> and <oLoans> to <groupC>.
The line:
if (e.Source.CreateNavigator().SelectSingleNode("ancestor::my:oFacilities/my:oProposed/my:oLoans",
instead of:
if (MainDataSource.CreateNavigator().SelectSingleNode("/my:Case/my:Facilities/my:Proposed/my:Loans",
is to blame. The root node of the e.Source is the node relating to the context of the button so there is no ancestor to go up to, but if we go down through MainDataSource, how do we indicate the context of the upper repeating structure?
When looking into the original problem, a colleague suggested using a calculated field to give the position() of the row. I think that this might offer the solution to this problem, i.e. adding a calculated field in the lower repeating structure which stores the position() in the upper structure. I'll try this, but please offer a solution if you can think of one!
Stu