I populated a pdf from some fields that are coming from XML in C# code.
I have to put dash (-) for each empty field. Should I check each time if the field is empty put the dash or there is a way to do it for all the fields at once?
What is the best way as I have 50 fields to check.
that is the code I have now:
dt.LastName = (dt.LastName == null ? null : (string)individual.XPathSelectElement("AIndividual[#Type='Co-Applicant']/GivenName/LastName"));
if (dt.LastName == null)
dt.LastName = "-";
I presume dt.LastName originally comes form the same document from another AIndividual element. In this case you could process your document using an array of XPath selectors and property setters. (Mind the code below is a rough sketch and not even compiled):
public class Applicant
{
public string LastName { get; set;}
}
public void Process(XmlElement application, Applicant applicant)
{
var selectors = new[] {
new {
Setter = new Action<Applicant, string>((t,v) => t.LastName = v),
XPath = "GivenName/LastName"
}
};
foreach(var selector in selectors)
{
var node = application.SelectSingleNode("AIndividual[#Type='PrimaryApplicant']/" + selector.XPath) ??
application.SelectSingleNode("AIndividual[#Type='CoApplicant']/" + selector.XPath);
selector.Setter(applicant, node == null ? "-" : node.Value);
}
}
Related
I have a if-else if construct where in I am setting a particular value of a variable based on the XName Element local name as follows:
public struct UserObject
{
public string rawValue;
}
var xmlElements= record.Descendants("abc")
.Select(x => x.Elements().ToArray());
foreach (XElement[] elements in xmlElements)
{
foreach (XElement element in elements)
{
UserObject userObject = new UserObject();
if (element.Name.LocalName == "b036") //"b036" is a XML element tag name
userObject.rawValue = (element.Value.Trim()); //note rawvalue is of string type
else if (element.Name.LocalName == "b037")
userObject.rawValue = (element.Value.Trim());
else if (element.Name.LocalName == "b040")
userObject.rawValue = (element.Value.Trim());
}
For the name of the userObject(rawvalue) to load I want to follow this hierarchical order :-
b036, PersonName (e.g., John Smith) if not available use b037
b037, PersonName (e.g., Smith, John) if not available use b040
b040, KeyNames, a.k.a Last Name (e.g., Smith)
If none of b036, b037 or b040 are found, I do not want to set the "rawvalue" for that record
How can I construct my if-else statements or should I use switch case statements to achieve the same?
Since you want to find the value for the highest of certain elements, do a max search. By rolling your own, you avoid having to scan or test twice.
First, create a variable to represent the precedence of the interesting names:
var hierarchy = new[] { "b040", "b037", "b036" };
Now setup some variables to remember the maximum candidate found so far:
XElement candidate = null;
int candidatePos = -1;
Finally, go through all the XMLElement values and remember the maximum found:
foreach (var element in xmlElements.SelectMany(elements => elements)) {
var pos = Array.IndexOf(hierarchy, element.Name.LocalName);
if (pos >= 0) {
if (candidate == null || pos > candidatePos) {
candidate = element;
candidatePos = pos;
}
}
}
If you found a maximum, you can work with it:
if (candidate != null) { //"b036" is a XML element tag name
UserObject userObject = new UserObject();
userObject.rawValue = (candidate.Value.Trim()); //note rawvalue is of string type
// work with userObject
}
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}");
}
I have a method called GetMenuItems which returns Heirarchical results. Here is the implementation:
public static ObservableCollection<MenuItem> GetMenuItems()
{
XDocument xDoc = XDocument.Load(DirectoryPaths.DataDirectory_General + "MenuItems.xml");
return LoadMenuItems(xDoc.Descendants("MenuItem"));
}
private static ObservableCollection<MenuItem> LoadMenuItems(IEnumerable<XElement> menuItems)
{
return new ObservableCollection<MenuItem>(
menuItems.Select(
x => new MenuItem()
{
Id = Convert.ToDouble(x.Attribute("Id").Value),
Name = x.Element("Name").Value,
ImageData = x.Elements("ImageData").Any() ? x.Element("ImageData").Value : "",
Angle = x.Elements("Angle").Any() ? Convert.ToDouble(x.Element("Angle").Value) : 0,
ScaleX = x.Elements("ScaleX").Any() ? Convert.ToInt32(x.Element("ScaleX").Value) : 0,
ScaleY = x.Elements("ScaleY").Any() ? Convert.ToInt32(x.Element("ScaleY").Value) : 0,
ShortcutKey = x.Elements("ShortcutKey").Any() ? x.Element("ShortcutKey").Value : "",
Background = x.Elements("Background").Any() ? x.Element("Background").Value : "#FF000000",
MouseOver = x.Elements("MouseOver").Any() ? x.Element("MouseOver").Value : "#FF696969",
menuItem = x.Elements("MenuItem").Any() ? LoadMenuItems(x.Elements("MenuItem")) : null
}
)
);
}
Now I want to get all the direct children of a specific Parent.
To make it more clear let me give an example:
Suppose I want to get all the direct children MenuItems of MenuItem whose Id = 1.
Please note that I need to use GetMenuItems() method as I am not allowed to access those XML Files.
You should split your task into two parts:
Finding the menu with a particular ID
Getting its children
The latter is simple - you just use the menuItem property, which would be better named Children or something similar.
I'd tackle the first part by recursion - after making one important change. Instead of the Children property being null if there are no elements, just let it be an empty collection:
Children = LoadMenuItems(x.Elements("MenuItem")
That way, you can check all the children very easily, even if there aren't any - without any nullity checks. Generally, it's easier to represent a lack of items as an empty collection rather than a null reference.
So, to recursively find a menu item by ID, I'd use:
// TODO: Change the ID type from double to almost anything else. double is a
// *terrible* type to use for IDs.
public MenuItem FindMenuItemById(MenuItem item, double id)
{
return item.Id == id ? item : item.Children
.Select(x => FindMenuItemById(x, id))
.Where(found => found != null)
.FirstOrDefault();
}
That will return null if there's no such menu item. Then you can just use:
if (item != null)
{
var children = item.Children;
...
}
As an aside, your other properties can be converted much more simply using the conversion operators on XElement and the null-coalescing operator
// Again, change this! Don't use double!
Id = (double) x.Attribute("Id"),
Name = (string) x.Element("Name"),
ImageData = (string) x.Element("ImageData") ?? "",
Angle = (double?) x.Element("Angle") ?? 0d,
ScaleX = (double?) x.Element("ScaleX") ?? 0d,
ScaleY = (double?) x.Element("ScaleY") ?? 0d,
ShortcutKey = (string) x.Element("ShortcutKey") ?? "",
Background = (string) x.Element("Background") ?? "#FF000000",
MouseOver = (string) x.Element("MouseOver") ?? "#FF696969",
I'm trying to parse an XML file from UN website (http://www.un.org/sc/committees/1267/AQList.xml) using c#.
There is one problem I'm constantly having with this file, and that's the number of child tags varies from one <.INDIVIDUAL.> tag to another. One example is <.FORTH_NAME.> child tag.
I've tried a number of different approaches, but somehow I always seem to be stuck with the same problem, and that's different number of child tags inside <.INDIVIDUAL.> tag.
What I'm trying to achieve is to collect all the tags and their values under one <.INDIVIDUAL.> tag, and then insert only those I want into my database. If a tag is missing, for example <.FOURTH_NAME.>, than I need to insert only first three names into the database, and skip the fourth.
I've tried using Linq to XML, and here are some examples:
XDocument xdoc = XDocument.Load(path);
var tags = (from t in xdoc.Descendants("INDIVIDUALS")
from a in t.Elements("INDIVIDUAL")
select new
{
Tag = a.Name,
val = a.Value
});
foreach (var obj in tags)
{
Console.WriteLine(obj.Tag + " - " + obj.val + "\t");
//insert SQL goes here
}
or:
but this one only collects non empty FOURTH_NAME tags...
var q = (from c in xdoc.Descendants("INDIVIDUAL")
from _1 in c.Elements("FIRST_NAME")
from _2 in c.Elements("SECOND_NAME")
from _3 in c.Elements("THIRD_NAME")
from _4 in c.Elements("FOURTH_NAME")
where _1 != null && _2 != null && _3 != null && _4 != null
select new
{
_1 = c.Element("FIRST_NAME").Value,
_2 = c.Element("SECOND_NAME").Value,
_3 = c.Element("THIRD_NAME").Value,
_4 = c.Element("FOURTH_NAME").Value
});
foreach (var obj in q)
{
Console.WriteLine("Person: " + obj._1 + " - " + obj._2 + " - " + obj._3 + " - " + obj._4);
//insert SQL goes here
}
Any ideas??
Instead of calling Value on the element, consider using a string cast. LINQ to XML safely returns null if the element doesn't exist. Try the following:
var data = XElement.Load(#"http://www.un.org/sc/committees/1267/AQList.xml");
var individuals = data.Descendants("INDIVIDUAL")
.Select(i => new {
First = (string)i.Element("FIRST_NAME"),
Middle = (string)i.Element("SECOND_NAME"),
Last = (string)i.Element("THIRD_NAME")
});
If you want to be more flexible and get all of the name fields, you can do something like the following. (I'll leave the process of grouping individuals as an additional homework assignment ;-)
data.Descendants("INDIVIDUAL").Elements()
.Where (i =>i.Name.LocalName.EndsWith("_NAME" ))
.Select(i => new { FieldName= i.Name.LocalName, Value=i.Value});
Why don't you use XmlSerializer and LINQ instead ?
As explained in this answer, generate your classes by pasting in a new CS file :
menu EDIT > Paste Special > Paste XML As Classes.
Then grab your data as easily as follows :
var serializer = new XmlSerializer(typeof (CONSOLIDATED_LIST));
using (FileStream fileStream = File.OpenRead(#"..\..\aqlist.xml"))
{
var list = serializer.Deserialize(fileStream) as CONSOLIDATED_LIST;
if (list != null)
{
var enumerable = list.INDIVIDUALS.Select(s => new
{
FirstName = s.FIRST_NAME,
SecondName = s.SECOND_NAME,
ThirdName = s.THIRD_NAME,
FourthName = s.FOURTH_NAME
});
}
}
You can then specify any predicate that better suits your needs.
Going this path will be a huge time-saver and less error-prone, no need to use strings to access fields, strong typing etc ...
I am trying to make a dynamic linq query that will check for values based on a string.
First of all, here's the query:
objQry = from o in m_Db.OBJECTS.Where(whereConditions)
select o;
if(!objQry.Any())
{
return null;
}
The whereConditions variable is a string I build and pass as parameter to find out the values I need. Here's examples of valid string:
OBJ_NAME == \"Sword\" and OBJ_OWNER == \"Stan\"
This will return any item whose name is "Sword" and owner is "Stan;
OBJ_COLOR == \"Blue\" OR OBJ_COLOR == \"Red\"
This will return any item which color is either blue or red.
Up to there, I'm fine, but now I have a problem: I need to check a decimal field. So I've tried this string:
OBJ_NUMBER == 1
But the query returns null even if there are objects which OBJ_NUMBER value is 1. It's a decimal. How can I indicate the query that they need to check for a decimal value?
**** EDIT ****
I have tried to "modify" the value passed so that it looks like this:
"CARD_NUMBER == Convert.ToDecimal(1)"
And now I have a different kind of error telling me this:
LINQ to Entities does not recognize the method 'System.Decimal ToDecimal(Int32)' method, and this method cannot be translated into a store expression.
Any clues anyone? I'm still looking for a way to do this. Thanks!
EDIT 2
You can get an example of how my code is shaped by looking at this question.
Let's come back at this problem. I want to check decimal values. Let's say that OBJ_NUMBER is a decimal field.
Using Dynamic Linq, I tried to read the decimal field. Say that I want to get each object which number is 1.27. The whereConditions field would then be shaped like this:
OBJ_NUMBER == 1.27
But then I would get an Invalid real literal '1.27' error. I don't know why.
So I have tried Gert Arnold's solution and done this instead:
decimal bDecimal = decimal.Parce(valueToParse);
param = new ObjectParameter("cardNumber", typeof(decimal)) { Value = bDecimal };
valuesToUse.Add("CARD_NUMBER == #cardNumber");
listParams.Add(param);
But I ended up having 2 problems:
The first problem is that my whereConditions string is shaped this way:
CARD_NUMBER == #cardNumber
But I get the following error:
No property or field 'cardNumber' exists in type 'CARD'
Leading me to believe that it cannot make the link between the object parameter and the string used to do the query.
As you can see, I have a list of Params. This is because I cannot know for sure how many parameters the user will chose. So each time the user enters a new search field, I have to create a new ObjectParameter and store it in a list. Here's how I try to do the thing after:
ObjectParameter[] arrayParameters = listParams.ToArray();
// Convert the list to an array
And then, when I try to make the query:
cardQry = from c in mDb.CARD.Where(whereConditions, arrayParameters)
select c;
But to no avail.
RESULTS
Based on the answered question below, I have developped something "awful", yet functional.
First of all, I ignore every decimal fields because I could never reach them with dynamic linq. Instead, I do this:
var valuesToParse = keyValuePair.Value.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);
// Here I parse the value and, if that's the case, the symbol.
decimal baseValue = decimal.Parse(valuesToParse[0]);
if (valuesToParse.Count() > 1)
{
string baseMethod = valuesToParse[1];
if (baseMethod == ">" || baseMethod == ">=")
{
if (baseMethod == ">=")
{
baseValue--;
}
// The list is actually like this: Dictionary<string, object> list = new Dictionary<string, object>();
list.Add("low", baseValue);
// I kind of activate a tag telling me that the user is looking for a higher value.
cardHigher = true;
}
else
{
if (baseMethod == "<=")
{
baseValue++;
}
list.Add("low", baseValue);
cardLower = true;
}
}
else
{
//lowParam = new ObjectParameter("dec", typeof(decimal)) { Value = baseValue };
list.Add("low", baseValue);
}
cardNumberActivated = true;
At the end, when I get the list of objects, I do this:
if (list.Count > 0)
{
(example)
if (cardNumberActivated)
{
if (cardHigher)
{
q = mDb.CARD.Where("CARD_NUMBER >= #0", list["low"]).ToList();
}
else if (cardLower)
{
q = mDb.CARD.Where("CARD_NUMBER <= #0", list["low"]).ToList();
}
else
{
q = mDb.CARD.Where("CARD_NUMBER == #0", list["low"]).ToList();
}
}
}
// Here we get the orinalData with the basic filters.
listToReturn.AddRange(cardQry);
if (q != null)
{
//listToReturn.AddRange(q);
for (int i = 0; i < listToReturn.Count; i++)
{
var priceList1 = listToReturn[i];
if (!q.Any(_item => _item.CARD_NUMBER == priceList1.CARD_NUMBER))
{
listToReturn.RemoveAt(i);
i--;
}
}
}
And it works. This is not an elegant way to make it work, but I can validate the fields the way I wanted, and for this, I am thankful at last.
You should not build a query string with inline predicate values. Use parameters in stead. Then will also be able to specify the type:
var whereConditions= "it.CARD_NUMBER = #cardNumber";
var param = new ObjectParameter("cardNumber", typeof(decimal)) { Value = 1 };
objQry = from o in m_Db.OBJECTS.Where(whereConditions, param);
Edit
I don't know what doesn't work in your code. Here's just a random piece of working code derived from one of my own projects:
var param1 = new ObjectParameter("dec", typeof(decimal)) { Value = 90000m };
var param2 = new ObjectParameter("int", typeof(int)) { Value = 90000 };
var q = ValueHolders.Where("it.DecimalValue >= #dec OR it.IntegerValue > #int",
param1, param2).ToList();
Note that param1, param2 could also be an array of ObjectParameter.