How to merge two NodebyID into one variable? - c#

I am using Umbraco and I would like to add two variables together that will display articles in both children.
var nodes = Model.NodeById(1195).Children();
var nodes2 = Model.NodeById(1201).Children();
var test = Model.NodesById(nodes, nodes2);
It's not working and throwing an error. Is there another way to do this?
I found this on the forum board, but It doesn't seem to work for me.
link: http://our.umbraco.org/forum/developers/razor/47078-how-to-merger-DynamicNode?p=0#comment168589

Something like this perhaps?
DynamicNodeList nodes = Model.NodeById(1195).Children();
DynamicNodeList nodes2 = Model.NodeById(1201).Children();
var allNodes = nodes.Concat(nodes2);

A bit primitive (but without knowing more of the context) something like this should work:
string parentIds = "1195,1201";
string[] parentArray = parentIds.Split(',');
DynamicNodeList allNodes = new DynamicNodeList();
foreach (var x in parentArray);
foreach (var y in Library.NodeById(x).Children()) {
var thisNode = Library.NodeById(y);
if (thisNode.Id != 0) {
allNodes.Add(thisNode);
}
}
}

Related

C# Read and Store Data from XML

I am trying to read and store data from an xml file. I have been reading about various methods to read the data such as XmlReader, XmlTextReader, LinQ, etc.
My XML file is
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<circuit name="local">
<Device>device1</Device>
<Point>point1></Point>
</circuit>
<circuit name ="remote">
<Device>device2</Device>
<Point>point2</Point>
</circuit>
</configuration>
I am trying to extract Device and Point set so I can pass those along to be used in a database query. I used this code and the foreach loop to verify the contents, but it only gets the first set.
XDocument msrDoc = XDocument.Load("BNOC MSR.config");
var data = from item in msrDoc.Descendants("circuit")
select new
{
device = item.Element("Device").Value,
point = item.Element("Point").Value
};
foreach (var p in data)
Console.WriteLine(p.ToString());
I have also tried this, but my arrays were all null
String[] deviceList = new String[1];
String[] pointList = new String[1];
int n = 0;
XmlDocument msrDoc = new XmlDocument();
msrDoc.Load("BNOC MSR.config");
var itemNodes = msrDoc.SelectNodes("circuit");
foreach (XmlNode node in itemNodes)
{
var circuit = node.SelectNodes("circuit");
foreach (XmlNode cir in circuit)
{
deviceList[n] = cir.SelectSingleNode("Device").InnerText;
pointList[n] = cir.SelectSingleNode("Point").InnerText;
}
}
Any help would be greatly appreciated.
Are you sure you don't want to use the built-in Properties.Settings for this?
Circuit local = Properties.Settings.Default.localCircuit;
Circuit remote = Properties.Settings.Default.remoteCircuit;
https://learn.microsoft.com/en-us/dotnet/framework/winforms/advanced/using-application-settings-and-user-settings
I believe there is something wrong with the way you are testing the result. The code:
void Main()
{
var fileLocation = #"C:\BrianTemp\input.txt";
var xml = File.ReadAllText(fileLocation);
XDocument msrDoc = XDocument.Load(fileLocation);
var data = from item in msrDoc.Descendants("circuit")
select new
{
device = item.Element("Device").Value,
point = item.Element("Point").Value
};
foreach (var p in data)
{
//It is best practice to use statement blocks {} to prevent silly errors.
//Sometimes you want to execute multiple statements, especially as code changes later
Console.WriteLine($"{p}");
}
}
Produces the expected output:
{ device = device1, point = point1 }
{ device = device2, point = point2 }
You said:
I used this code and the foreach loop to verify the contents, but it
only gets the first set.
As you can see the code produces 2 results as it should.
Note: I corrected the XML file to remove the extra >
<Point>point1></Point><==
I see two problems in your code (and I only tried the second method you posted):
Your string arrays are too small, change to:
String[] deviceList = new String[1];
String[] pointList = new String[1];
The line var itemNodes = msrDoc.SelectNodes("circuit"); should be
var itemNodes = msrDoc.SelectNodes("configuration");

C# Linq get descendants on a subquery

I've been banging my head on the desktop for the past couple of hours trying to decipher this issue.
I'm trying to query an XML file with Linq, the xml has the following format:
<MRLGroups>
<MRLGroup>
<MarketID>6084</MarketID>
<MarketName>European Union</MarketName>
<ActiveIngredientID>28307</ActiveIngredientID>
<ActiveIngredientName>2,4-DB</ActiveIngredientName>
<IndexCommodityID>59916</IndexCommodityID>
<IndexCommodityName>Cucumber</IndexCommodityName>
<ScientificName>Cucumis sativus</ScientificName>
<MRLs>
<MRL>
<PublishedCommodityID>60625</PublishedCommodityID>
<PublishedCommodityName>Cucumbers</PublishedCommodityName>
<MRLTypeID>238</MRLTypeID>
<MRLTypeName>General</MRLTypeName>
<DeferredToMarketID>6084</DeferredToMarketID>
<DeferredToMarketName>European Union</DeferredToMarketName>
<UndefinedCommodityLinkInd>false</UndefinedCommodityLinkInd>
<MRLValueInPPM>0.0100</MRLValueInPPM>
<ResidueDefinition>2,4-DB</ResidueDefinition>
<AdditionalRegulationNotes>Comments.</AdditionalRegulationNotes>
<ExpiryDate xsi:nil="true" />
<PrimaryInd>true</PrimaryInd>
<ExemptInd>false</ExemptInd>
</MRL>
<MRL>
<PublishedCommodityID>60626</PublishedCommodityID>
<PublishedCommodityName>Gherkins</PublishedCommodityName>
<MRLTypeID>238</MRLTypeID>
<MRLTypeName>General</MRLTypeName>
<DeferredToMarketID>6084</DeferredToMarketID>
<DeferredToMarketName>European Union</DeferredToMarketName>
<UndefinedCommodityLinkInd>false</UndefinedCommodityLinkInd>
<MRLValueInPPM>0.0100</MRLValueInPPM>
<ResidueDefinition>2,4-DB</ResidueDefinition>
<AdditionalRegulationNotes>More Comments.</AdditionalRegulationNotes>
<ExpiryDate xsi:nil="true" />
<PrimaryInd>false</PrimaryInd>
<ExemptInd>false</ExemptInd>
</MRL>
</MRLs>
</MRLGroup>
So far i've created classes for the "MRLGroup" section of the file
var queryMarket = from market in doc.Descendants("MRLGroup")
select new xMarketID
{
MarketID = Convert.ToString(market.Element("MarketID").Value),
MarketName = Convert.ToString(market.Element("MarketName").Value)
};
List<xMarketID> markets = queryMarket.Distinct().ToList();
var queryIngredient = from ingredient in doc.Descendants("MRLGroup")
select new xActiveIngredients
{
ActiveIngredientID = Convert.ToString(ingredient.Element("ActiveIngredientID").Value),
ActiveIngredientName = Convert.ToString(ingredient.Element("ActiveIngredientName").Value)
};
List<xActiveIngredients> ingredientes = queryIngredient.Distinct().ToList();
var queryCommodities = from commodity in doc.Descendants("MRLGroup")
select new xCommodities {
IndexCommodityID = Convert.ToString(commodity.Element("IndexCommodityID").Value),
IndexCommodityName = Convert.ToString(commodity.Element("IndexCommodityName").Value),
ScientificName = Convert.ToString(commodity.Element("ScientificName").Value)
};
List<xCommodities> commodities = queryCommodities.Distinct().ToList();
After i got the "catalogues" I'm trying to query the document against the catalogues to achieve some sort of "groups", after all this, i'm going to send this data to the database, the issue here is that the xml files are around 600MB each and i get the everyday, so my approach is to create catalogues and just send the MRLs to the database joined to the "header" table that contains the Catalogues IDs, here's what i've done so far but failed miserably:
//markets
foreach (xMarketID market in markets) {
//ingredients
foreach (xActiveIngredients ingredient in ingredientes) {
//commodities
foreach (xCommodities commodity in commodities) {
var mrls = from m in doc.Descendants("MRLGroup")
where Convert.ToString(m.Element("MarketID").Value) == market.MarketID
&& Convert.ToString(m.Element("ActiveIngredientID").Value) == ingredient.ActiveIngredientID
&& Convert.ToString(m.Element("IndexCommodityID").Value) == commodity.IndexCommodityID
select new
{
ms = new List<xMRLIndividial>(from a in m.Element("MRLs").Descendants()
select new xMRLIndividial{
publishedCommodityID = string.IsNullOrEmpty(a.Element("PublishedCommodityID").Value) ? "" : a.Element("PublishedCommodityID").Value,
publishedCommodityName = a.Element("PublishedCommodityName").Value,
mrlTypeId = a.Element("MRLTypeID").Value,
mrlTypeName = a.Element("MRLTypeName").Value,
deferredToMarketId = a.Element("DeferredToMarketID").Value,
deferredToMarketName = a.Element("DeferredToMarketName").Value,
undefinedCommodityLinkId = a.Element("UndefinedCommodityLinkInd").Value,
mrlValueInPPM = a.Element("MRLValueInPPM").Value,
residueDefinition = a.Element("ResidueDefinition").Value,
additionalRegulationNotes = a.Element("AdditionalRegulationNotes").Value,
expiryDate = a.Element("ExpiryDate").Value,
primaryInd = a.Element("PrimaryInd").Value,
exemptInd = a.Element("ExemptInd").Value
})
};
foreach (var item in mrls)
{
Console.WriteLine(item.ToString());
}
}
}
}
If you notice i'm trying to get just the MRLs descendants but i got this error:
All i can reach on the "a" variable is the very first node of MRLs->MRL not all of them, what is going on?
If you guys could lend me a hand would be super!
Thanks in advance.
With this line...
from a in m.Element("MRLs").Descendants()
...will iterate through all sub-elements, including children of children. Hence your error, since your <PublishedCommodityID> element does not have a child element.
Unless you want to specifically return all child elements of all levels, always use the Element and Elements axis instead of Descendant and Descendants:
from a in m.Element("MRLs").Elements()
That should solve your problem.
However, your query is also difficult to read with the nested foreach loops and the multiple tests for the IDs. You can simplify it with a combination of LINQ and XPath:
var mrls =
from market in markets
from ingredient in ingredientes
from commodity in commodities
let xpath = $"/MRLGroups/MRLGroup[{market.MarketId}]" +
$"[ActiveIngredientID={ingredient.ActiveIngredientId}]" +
$"[IndexCommodityID={commodity.IndexCommodityID}]/MRLs/MRL"
select new {
ms =
(from a in doc.XPathSelectElements(xpath)
select new xMRLIndividial {
publishedCommodityID = string.IsNullOrEmpty(a.Element("PublishedCommodityID").Value) ? "" : a.Element("PublishedCommodityID").Value,
publishedCommodityName = a.Element("PublishedCommodityName").Value,
mrlTypeId = a.Element("MRLTypeID").Value,
mrlTypeName = a.Element("MRLTypeName").Value,
deferredToMarketId = a.Element("DeferredToMarketID").Value,
deferredToMarketName = a.Element("DeferredToMarketName").Value,
undefinedCommodityLinkId = a.Element("UndefinedCommodityLinkInd").Value,
mrlValueInPPM = a.Element("MRLValueInPPM").Value,
residueDefinition = a.Element("ResidueDefinition").Value,
additionalRegulationNotes = a.Element("AdditionalRegulationNotes").Value,
expiryDate = a.Element("ExpiryDate").Value,
primaryInd = a.Element("PrimaryInd").Value,
exemptInd = a.Element("ExemptInd").Value
}).ToList()
};

How to get list items without for each in MVC controller

I need to access items from a list which is i am accessing with the following code
foreach (var reportval in reportresponse)
{
foreach (var valitem in reportval.Comparison)
{
var responsemodel = new ReportResponseModel();
responsemodel.StudentVariable = valitem.StudentVariable;
responsemodel.Lighter = valitem.Lighter;
responsemodel.Matched = valitem.Matched;
responsemodel.Stronger = valitem.Stronger;
reportResponseModel.Add(responsemodel);
}
};
I tried the following code to exit the loop without retiterting the first loop. But its not working.
if (reportresponse.Count == reportResponseModel.Count) { break; };
also i tried the following way to access the inner list from the first loop but its not accessible here
foreach (var reportval in reportresponse.Comparison)
Can someone please help on this?
Did you try like this
foreach (var reportval in reportresponse.Comparison)
{
// var responsemodel = new ReportResponseModel();
responsemodel.StudentVariable = valitem.StudentVariable;
responsemodel.Lighter = reportval .Lighter;
responsemodel.Matched = reportval .Matched;
responsemodel.Stronger = reportval .Stronger;
//reportResponseModel.Add(responsemodel);
}
};
Have you tried Linq's SelectMany?
You can do something like
var reportResponseModel = reportresponse.SelectMany(r => r.Comparison, (r, c) =>
new ReportResponseModel
{
StudentVariable = c.StudentVariable,
Lighter = c.Lighter,
Matched = c.Matched,
Stronger = c.Stronger
});
Then you can apply additional filtering like with .Where or .Take to have only needed count of items.
I updated the code with the following changes.
if (reportresponse.Count == reportResponseModel.Count)
{ return reportResponseModel; };
after
reportResponseModel.Add(responsemodel);
Thanks #Stephen Muecke !!

Neo4j: How to return multiple paths from different starting nodes

I have a question similar to
this question but I am using the c# with the neo4jClient instead of the Java.
I can get the parent path of a given node with the following code but it becomes a performance bottle neck when trying to find the parent path of many nodes. What I would like is a way to call the graph database once with a list of node keys and get back a list of parent paths. So that I can return a dictionary of results instead of a single list.
Any help accomplishing this would be greatly appreciated! Also if my original cypher query can be improved I'm open to that as well.
public IEnumerable<IGenericEntity> GetPath(string entityCompositeKey, GraphRelationship relationship)
{
var entity = new GenericEntity();
entity.setCompositeKey(entityCompositeKey);
var pathToRoot = new List<GenericEntity>(){ entity };
var query = new CypherFluentQuery(graphClient)
.Match("p = (current)-[r:" + relationship.Name + "*0..]->()")
.Where((IGenericEntity current) => current.CompositeKey == entityCompositeKey)
.Return(() => Return.As<IEnumerable<GenericEntity>>("nodes(p)"))
.OrderByDescending("length(p)")
.Limit(10);
var queryText = query.Query.QueryText;
var paramText = query.Query.QueryParameters;
if (query.Results != null)
{
var graphResults = query.Results.FirstOrDefault();
if (graphResults != null && graphResults.ToList().Count > 0)
{
pathToRoot = graphResults.ToList();
}
}
return pathToRoot;
}
There are a few things I'm not sure of - and it's most likely how my test DB is setup.
To answer the initial question of how to pass in multiple start nodes - that's probably best approached using the UNWIND operator, which in Neo4jClient is used like so:
var enumerable = new string[] { "a", "b" }
client.Unwind(enumerable, "item"). /*The rest*/
Obvs, if you place that in the top of your current query you'll get a monster set of nodes back, and you won't know which Root entity refers to which, soo... let's do some projecting...
To project, we must have something to project into:
public class Result {
public GenericEntity Root { get; set; }
public List<GenericEntity> Nodes { get; set; }
public int Length { get; set; }
}
This will contain the Root node, and the path to it, now to fill.
public IEnumerable<Result> GetPath(IEnumerable<string> rootKeys, GraphRelationship relationship)
{
var query = new CypherFluentQuery(Client)
.Unwind(rootKeys, "entityRootKey")
.Match(string.Format("p = (root)-[r:{0}*0..]->()", relationship.Name))
.Where("root.CompositeKey = entityRootKey")
.With("{Root:root, Nodes: nodes(p), Length: length(p)} as res")
.Return((res) => res.As<Result>())
.OrderByDescending("res.Length")
.Limit(10);
var results = query.Results;
return results;
}
I'm not using .Where with a parameter creating Func<T> this is because the parameter is created in the .Unwind statement.
Usage wise - something like this:
var res = GetPath(new[] {"a", "b"}, new GraphRelationship {Name = "RELATED"});
foreach (var result in res)
{
Console.WriteLine($"{result.Root.CompositeKey} => {result.Length}");
foreach (var node in result.Nodes)
Console.WriteLine($"\t{node.CompositeKey}");
}

How do I create a new root by adding and removing nodes retrieved from the old root?

I am creating a Code Fix that changes this:
if(obj is MyClass)
{
var castedObj = obj as MyClass;
}
into this:
var castedObj = obj as MyClass;
if(castedObj != null)
{
}
This means I have to do 3 things:
Change the condition in the if statement.
Move the casting right above the if statement.
Remove the statement in the body.
So far, all my attempts have stranded me at getting at most 2 of these things to work.
I believe this problem occurs because you basically have 2 syntax nodes on the same level. As such, making a change to one of them invalidates the location of the other one. Or something like that. Long story short: I either manage to copy the variable assignment outside the if statement, or I manage to change the condition + remove the variable assignment. Never all 3.
How would I solve this?
For good measure, here is my code which changes the condition and removes the assignment:
var newIfStatement = ifStatement.RemoveNode(
variableDeclaration,
SyntaxRemoveOptions.KeepExteriorTrivia);
newIfStatement = newIfStatement.ReplaceNode(newIfStatement.Condition, newCondition);
var ifParent = ifStatement.Parent;
var newParent = ifParent.ReplaceNode(ifStatement, newIfStatement);
newParent = newParent.InsertNodesBefore(
newIfStatement,
new[] { variableDeclaration })
.WithAdditionalAnnotations(Formatter.Annotation);
var newRoot = root.ReplaceNode(ifParent, newParent);
Have you looked at the DocumentEditor class ? It is very useful when dealing with modifying syntax, especially when the changes that are applied to the tree might cause invalidation problems. The operations are pretty much the same as the ones you already have defined, just use the DocumentEditor methods instead and see if that helps. I can't verify if that solves your problem ATM, but I think it solved the a similar problem for me once in the past. I'll test it out later if I can.
Something like this will do it:
var editor = await DocumentEditor.CreateAsync(document);
editor.RemoveNode(variableDeclaration);
editor.ReplaceNode(ifStatement.Condition, newCondition);
editor.InsertBefore(ifStatement,
new[] { variableDeclaration.WithAdditionalAnnotations(Formatter.Annotation) });
var newDocument = editor.GetChangedDocument();
I have managed to do something very similar in the following manner.
I extract the while condition and move it before the while and replace the condition with a new node.
In the body of while, I add a new statement.
In your case, instead of adding a statement, you will remove the desired statement from the body.
Start at
Refactor(BlockSyntax oldBody)
STEP 1: I first visit and mark the nodes that I want to change and at the same time generate new nodes, but don't add the new ones yet.
STEP 2: Track the marked nodes and replace with new ones.
class WhileConditionRefactoringVisitor : CSharpSyntaxRewriter
{
private static int CONDITION_COUNTER = 0;
private static string CONDITION_VAR = "whileCondition_";
private static string ConditionIdentifier
{
get { return CONDITION_VAR + CONDITION_COUNTER++; }
}
private readonly List<SyntaxNode> markedNodes = new List<SyntaxNode>();
private readonly List<Tuple<ExpressionSyntax, IdentifierNameSyntax, StatementSyntax, WhileStatementSyntax>> replacementNodes =
new List<Tuple<ExpressionSyntax, IdentifierNameSyntax, StatementSyntax, WhileStatementSyntax>>();
//STEP 1
public override SyntaxNode VisitWhileStatement(WhileStatementSyntax node)
{
var nodeVisited = (WhileStatementSyntax) base.VisitWhileStatement(node);
var condition = nodeVisited.Condition;
if (condition.Kind() == SyntaxKind.IdentifierName)
return nodeVisited;
string conditionVarIdentifier = ConditionIdentifier;
var newConditionVar = SyntaxFactoryExtensions.GenerateLocalVariableDeclaration(conditionVarIdentifier,
condition, SyntaxKind.BoolKeyword).NormalizeWhitespace().WithTriviaFrom(nodeVisited);
var newCondition = SyntaxFactory.IdentifierName(conditionVarIdentifier).WithTriviaFrom(condition);
markedNodes.Add(condition);
markedNodes.Add(node);
replacementNodes.Add(new Tuple<ExpressionSyntax, IdentifierNameSyntax, StatementSyntax, WhileStatementSyntax>(condition, newCondition, newConditionVar, node));
return nodeVisited;
}
//STEP 2
private BlockSyntax ReplaceNodes(BlockSyntax oldBody)
{
oldBody = oldBody.TrackNodes(this.markedNodes);
foreach (var tuple in this.replacementNodes)
{
var currentA = oldBody.GetCurrentNode(tuple.Item1);
if (currentA != null)
{
var whileStatement = currentA.Parent;
oldBody = oldBody.InsertNodesBefore(whileStatement, new List<SyntaxNode>() { tuple.Item3 });
var currentB = oldBody.GetCurrentNode(tuple.Item1);
oldBody = oldBody.ReplaceNode(currentB, tuple.Item2);
var currentWhile = oldBody.GetCurrentNode(tuple.Item4);
//modify body
var whileBody = currentWhile.Statement as BlockSyntax;
//create new statement
var localCondition = tuple.Item3 as LocalDeclarationStatementSyntax;
var initializer = localCondition.Declaration.Variables.First();
var assignment = SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
SyntaxFactory.IdentifierName(initializer.Identifier), initializer.Initializer.Value));
var newStatements = whileBody.Statements.Add(assignment);
whileBody = whileBody.WithStatements(newStatements);
//updateWhile
var newWhile = currentWhile.WithStatement(whileBody);
oldBody = oldBody.ReplaceNode(currentWhile, newWhile);
}
}
return oldBody;
}
public BlockSyntax Refactor(BlockSyntax oldBody)
{
markedNodes.Clear();
replacementNodes.Clear();
//STEP 1
oldBody = (BlockSyntax)this.Visit(oldBody);
//STEP 2
oldBody = this.ReplaceNodes(oldBody);
return oldBody;
}
}

Categories

Resources