How to find XElement specific Children (in c# with LINQ)? - linq

I've got an XML file like this :
<root>
<environment env="PROD">
<key name="Big Key" propagate="true" value="21" />
</environment>
<environment env="PRE-PROD">
<key name="First Key" propagate="true" value="4" />
<key name="Second Key" propagate="true" value="3" />
</environment>
</root>
I want to check if a key exist in that file, and if the propagate item is true.
I manage to get those 2 System.Xml.Linq.XElement : key name="First Key" AND key name="Second Key".
but I would like to get only the one by pKeyname (like "Second Key" for eg.) I can't find how...
public static bool IsPropagate(string pXmlFileName, string pEnvironment, string pKeyname)
{
var doc = XElement.Load(pXmlFileName);
IEnumerable<XElement> childList = doc.Elements("environment")
.Where(elt => elt.Attribute("env").Value == pEnvironment)
.Elements();
if (childList.Any())
return true;
return false;
}
Any help would be highly appreciated!

This would help to get the exact key:
public static bool IsPropagate(string pXmlFileName, string pEnvironment,
string pKeyname)
{
var doc = XElement.Load(pXmlFileName);
IEnumerable<XElement> childList = doc.Elements("environment")
.Where(elt => elt.Attribute("env").Value == pEnvironment)
.Elements()
.Where(a => a.Attribute("name").Value == pKeyname);
if (childList.Any())
return true;
return false;
}

It's working by adding the "FirstOrDefault"! Thanks.
public static bool IsPropagate(string pXmlFileName, string pEnvironment, string pKeyname)
{
var doc = XElement.Load(pXmlFileName);
XElement child = doc.Elements("environment")
.Where(elt => elt.Attribute("env").Value == pEnvironment)
.Elements()
.FirstOrDefault(a => a.Attribute("name").Value == pKeyname);
if (child != null)
return true;
return false;
}

Related

Conversion of Visualforce page into LWC

Need help to convert my following VF page into LWC
VF code:
<apex:page showHeader="true" sidebar="true" controller="OrgWideOppBidContrl">
<apex:form >
<apex:pageBlock >
<apex:pageMessages id="pagMsg"/>
<apex:pageBlockSection >
<apex:pageBlockSectionItem >
<apex:outputText value="From" style="padding-top:5px;"/>
<apex:inputField value="{!opp.StartDate__c}" required="true"/>
</apex:pageBlockSectionItem>
<apex:pageBlockSectionItem >
<apex:outputText value="To" style="padding-top:5px;"/>
<apex:inputField value="{!opp.EstimatedHarvestDate__c}" required="true"/>
</apex:pageBlockSectionItem>
</apex:pageBlockSection>
<apex:commandButton value="start Batch " action="{!startBatchJob}" style="margin-left:500px;" reRender="pagMsg"/>
</apex:pageBlock>
</apex:form>
</apex:page>
Apex code:
public with sharing class OrgWideOppBidContrl {
public Opportunity opp{get;set;}
public OrgWideOppBidContrl(){
opp = new Opportunity();
opp.StartDate__c = Date.today();
opp.EstimatedHarvestDate__c = Date.today();
}
public PageReference startBatchJob(){
OrgWideOpportunityBidSetting__c orgwideOppBidSett = OrgWideOpportunityBidSetting__c.getInstance('OrgWideOppBid');
if(orgwideOppBidSett == null){
ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.ERROR,'OrgWideOppBid not found'));
return null;
}
if(orgwideOppBidSett.InProgress__c == true){
ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.WARNING,'Please wait Batch job for Org Wide Opportunity Bid is already in progress'));
return null;
}
String queryString = 'Select id From OrgWideMatch__c';
Database.executeBatch(new BatchExecutor(new DeleteOrgWideMatchData(), queryString, null), 1000);
ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.INFO,'Batch job for Org Wide Opportunity Bid is started successfully'));
orgwideOppBidSett.InProgress__c = true;
orgwideOppBidSett.startDate__c = opp.StartDate__c;
orgwideOppBidSett.EndDate__c = opp.EstimatedHarvestDate__c;
update orgwideOppBidSett;
return null;
}
}

Trying to understand how to conditionally write out element/attributes with LIINQToXML

This is the first time that I created a XML document using LINQToXML.
I am trying to understand how can I conditionally create attributes(or elements) when creating my document?
In this example a given car may/may not have a feature to it, so in that case I would not want to create that element, I also may have certain attributes in the feature node that could be missing. How could I handle these scenarios?
XDocument xDoc = new XDocument(
new XElement("root",
new XElement("NodeA"),
new XElement("Cars",
from p in listCars
select new XElement("Car", new XAttribute("name", p.CarName),
new XElement("Feature", new XAttribute("door", p.Door), new XAttribute("model", p.Model))
)
)
)
);
Desired result #1 (All features are missing for a given car):
<root>
<NodeA />
<Cars>
<Car name="Honda">
<Feature door="4" model="Accord" />
</Car>
<Car name="Ford" />
</Cars>
</root>
Desired result #2 (Some features could exist)
<root>
<NodeA />
<Cars>
<Car name="Honda">
<Feature door="4" model="Accord" />
</Car>
<Car name="Ford">
<Feature model="Focus" />
</Car>
</Cars>
</root>
2 seperate solutions in here. Either use a method to create the features node, or do it all in one:
static void Main(string[] args)
{
var listCars = new List<Car>();
listCars.Add(new Car { CarName = "test 1", Door = "0", Model = "" });
listCars.Add(new Car { CarName = "test 2", Door = "", Model = "" });
listCars.Add(new Car { CarName = "test 3", Door = "0", Model = "0" });
XDocument xDoc2 = new XDocument(
new XElement("root",
new XElement("NodeA"),
new XElement("Cars",
from p in listCars
select new XElement("Car",
new XAttribute("name", p.CarName),
p.Door != "" || p.Model != "" ?
new XElement("Feature",
p.Door != "" ? new XAttribute("door", p.Door) : null,
p.Model != "" ? new XAttribute("model", p.Model) : null) : null
)
)
)
);
XDocument xDoc = new XDocument(
new XElement("root",
new XElement("NodeA"),
new XElement("Cars",
from p in listCars
select new XElement("Car",
new XAttribute("name", p.CarName),
CreateFeature(p)
)
)
)
);
}
static XElement CreateFeature(Car p)
{
var el = new XElement("Feature",
p.Door != "" ? new XAttribute("door", p.Door) : null,
p.Model != "" ? new XAttribute("model", p.Model) : null);
return !el.Attributes().Any() ? null : el;
}
If you supply null instead of an element, it will be ignored, so you can use constructs like the following.
p.CarName != null ? new XAttribute("name", p.CarName) : null
If you're using C# 6, you can use null propagation.

Can I 'flatten' an XDocument with Linq?

I have a heavily nested XML document that I need to load into my db for additional processing. For various reasons beyond the scope of this discussion I need to 'flatten' that structure down, then load it into a DataTables and then I can SQLBulkCopy it into the db where it will get processed. So assume my original XML looks something like this (mine is even more heavily nested, but this is the basic idea):
<data>
<report id="1234" name="XYZ">
<department id="234" name="Accounting">
<item id="ABCD" name="some item">
<detail id="detail1" value="1"/>
<detail id="detail2" value="2"/>
<detail id="detail3" value="3"/>
</item>
</department>
</report>
</data>
and I want to flatten that down into a single (albeit redundant) table structure where each attribute becomes a column (i.e. ReportId, ReportName, DepartmentId, DepartmentName, ItemId, ItemName, Detail1, Detail2, Detail3).
So my question is simply 'is it possible to accomplish this with a simple Linq query'? In the past I would just write some XSLT and be done with it but I'm curious if the Linq library can accomplish the same thing?
thanks!
Is this what you're looking for?
var doc = XDocument.Load(fileName);
var details =
from report in doc.Root.Elements("report")
from department in report.Elements("department")
from item in department.Elements("item")
from detail in item.Elements("detail")
select new
{
ReportId = (int)report.Attribute("id"),
ReportName = (string)report.Attribute("name"),
DepartmentId = (int)department.Attribute("id"),
DepartmentName = (string)department.Attribute("name"),
ItemId = (string)item.Attribute("id"),
ItemName = (string)item.Attribute("name"),
DetailId = (string)detail.Attribute("id"),
DetailValue = (int)detail.Attribute("value"),
};
If you want it as a DataTable, you can use the following extension method:
public static DataTable ToDataTable<T>(this IEnumerable<T> source)
{
PropertyInfo[] properties = typeof(T).GetProperties()
.Where(p => p.CanRead && !p.GetIndexParameters().Any())
.ToArray();
DataTable table = new DataTable();
foreach (var p in properties)
{
Type type = p.PropertyType;
bool allowNull = !type.IsValueType;
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
allowNull = true;
type = Nullable.GetUnderlyingType(type);
}
DataColumn column = table.Columns.Add(p.Name, type);
column.AllowDBNull = allowNull;
column.ReadOnly = !p.CanWrite;
}
foreach (var item in source)
{
DataRow row = table.NewRow();
foreach (var p in properties)
{
object value = p.GetValue(item, null) ?? DBNull.Value;
row[p.Name] = value;
}
table.Rows.Add(row);
}
return table;
}
Use it like this:
var table = details.CopyToDataTable();

How can I do an OrderBy with a dynamic string parameter?

I want to do this:
var orderBy = "Nome, Cognome desc";
var timb = time.Timbratures.Include("Anagrafica_Dipendente")
.Where(p => p.CodDipendente == 1);
if(orderBy != "")
timb = timb.OrderBy(orderBy);
Is there an OrderBy overload available that accepts a string parameter?
If you are using plain LINQ-to-objects and don't want to take a dependency on an external library it is not hard to achieve what you want.
The OrderBy() clause accepts a Func<TSource, TKey> that gets a sort key from a source element. You can define the function outside the OrderBy() clause:
Func<Item, Object> orderByFunc = null;
You can then assign it to different values depending on the sort criteria:
if (sortOrder == SortOrder.SortByName)
orderByFunc = item => item.Name;
else if (sortOrder == SortOrder.SortByRank)
orderByFunc = item => item.Rank;
Then you can sort:
var sortedItems = items.OrderBy(orderByFunc);
This example assumes that the source type is Item that have properties Name and Rank.
Note that in this example TKey is Object to not constrain the property types that can be sorted on. If the func returns a value type (like Int32) it will get boxed when sorting and that is somewhat inefficient. If you can constrain TKey to a specific value type you can work around this problem.
Absolutely. You can use the LINQ Dynamic Query Library, found on Scott Guthrie's blog. There's also an updated version available on CodePlex.
It lets you create OrderBy clauses, Where clauses, and just about everything else by passing in string parameters. It works great for creating generic code for sorting/filtering grids, etc.
var result = data
.Where(/* ... */)
.Select(/* ... */)
.OrderBy("Foo asc");
var query = DbContext.Data
.Where(/* ... */)
.Select(/* ... */)
.OrderBy("Foo ascending");
Another solution from codeConcussion (https://stackoverflow.com/a/7265394/2793768)
var param = "Address";
var pi = typeof(Student).GetProperty(param);
var orderByAddress = items.OrderBy(x => pi.GetValue(x, null));
The simplest & the best solution:
mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s));
You don't need an external library for this. The below code works for LINQ to SQL/entities.
/// <summary>
/// Sorts the elements of a sequence according to a key and the sort order.
/// </summary>
/// <typeparam name="TSource">The type of the elements of <paramref name="query" />.</typeparam>
/// <param name="query">A sequence of values to order.</param>
/// <param name="key">Name of the property of <see cref="TSource"/> by which to sort the elements.</param>
/// <param name="ascending">True for ascending order, false for descending order.</param>
/// <returns>An <see cref="T:System.Linq.IOrderedQueryable`1" /> whose elements are sorted according to a key and sort order.</returns>
public static IQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> query, string key, bool ascending = true)
{
if (string.IsNullOrWhiteSpace(key))
{
return query;
}
var lambda = (dynamic)CreateExpression(typeof(TSource), key);
return ascending
? Queryable.OrderBy(query, lambda)
: Queryable.OrderByDescending(query, lambda);
}
private static LambdaExpression CreateExpression(Type type, string propertyName)
{
var param = Expression.Parameter(type, "x");
Expression body = param;
foreach (var member in propertyName.Split('.'))
{
body = Expression.PropertyOrField(body, member);
}
return Expression.Lambda(body, param);
}
(CreateExpression copied from https://stackoverflow.com/a/16208620/111438)
I did so:
using System.Linq.Expressions;
namespace System.Linq
{
public static class LinqExtensions
{
public static IOrderedQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string field, string dir = "asc")
{
// parametro => expressão
var parametro = Expression.Parameter(typeof(TSource), "r");
var expressao = Expression.Property(parametro, field);
var lambda = Expression.Lambda(expressao, parametro); // r => r.AlgumaCoisa
var tipo = typeof(TSource).GetProperty(field).PropertyType;
var nome = "OrderBy";
if (string.Equals(dir, "desc", StringComparison.InvariantCultureIgnoreCase))
{
nome = "OrderByDescending";
}
var metodo = typeof(Queryable).GetMethods().First(m => m.Name == nome && m.GetParameters().Length == 2);
var metodoGenerico = metodo.MakeGenericMethod(new[] { typeof(TSource), tipo });
return metodoGenerico.Invoke(source, new object[] { source, lambda }) as IOrderedQueryable<TSource>;
}
public static IOrderedQueryable<TSource> ThenBy<TSource>(this IOrderedQueryable<TSource> source, string field, string dir = "asc")
{
var parametro = Expression.Parameter(typeof(TSource), "r");
var expressao = Expression.Property(parametro, field);
var lambda = Expression.Lambda<Func<TSource, string>>(expressao, parametro); // r => r.AlgumaCoisa
var tipo = typeof(TSource).GetProperty(field).PropertyType;
var nome = "ThenBy";
if (string.Equals(dir, "desc", StringComparison.InvariantCultureIgnoreCase))
{
nome = "ThenByDescending";
}
var metodo = typeof(Queryable).GetMethods().First(m => m.Name == nome && m.GetParameters().Length == 2);
var metodoGenerico = metodo.MakeGenericMethod(new[] { typeof(TSource), tipo });
return metodoGenerico.Invoke(source, new object[] { source, lambda }) as IOrderedQueryable<TSource>;
}
}
}
Use :
example.OrderBy("Nome", "desc").ThenBy("other")
Work like:
example.OrderByDescending(r => r.Nome).ThenBy(r => r.other)
Look at this blog here. It describes a way to do this, by defining an EntitySorter<T>.
It allows you to pass in an IEntitySorter<T> into your service methods and use it like this:
public static Person[] GetAllPersons(IEntitySorter<Person> sorter)
{
using (var db = ContextFactory.CreateContext())
{
IOrderedQueryable<Person> sortedList = sorter.Sort(db.Persons);
return sortedList.ToArray();
}
}
And you can create an EntitiySorter like this:
IEntitySorter<Person> sorter = EntitySorter<Person>
.OrderBy(p => p.Name)
.ThenByDescending(p => p.Id);
Or like this:
var sorter = EntitySorter<Person>
.OrderByDescending("Address.City")
.ThenBy("Id");
You need to use the LINQ Dynamic Query Library in order to pass parameters at runtime,
This will allow linq statements like
string orderedBy = "Description";
var query = (from p in products
orderby(orderedBy)
select p);
If your columnName is in a variable col, then
string col="name";
list.OrderBy(x=>x[col])
As what Martin Liversage said, you can define a Func<>before you pass it to OrderBy method, but I found an interesting way to do that.
You can define a dictionary from string to Func<> like this :
Dictionary<string, Func<Item, object>> SortParameters = new Dictionary<string, Func<Item, object>>()
{
{"Rank", x => x.Rank}
};
And use it like this :
yourList.OrderBy(SortParameters["Rank"]);
In this case you can dynamically sort by string.
In one answer above:
The simplest & the best solution:
mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s));
There is an syntax error, ,null must be added:
mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s,null));

struts 2 checkboxlist validation question

I have struts 2 checkboxlist as followed:
<s:checkboxlist list="listOfOptions" name="someName" />
I would like to add validation to make sure that at least ONE of the checkboxes has been checked. Any thoughts?
Thanks
I use JS to do that.
<sx:submit
id="button_submit"
name="button_submit"
onclick="return validateNotEmptyCheckbox();" />
And JS:
function validateNotEmptyCheckbox() {
var checkboxes = document.getElementsByTagName('input');
for (i = 0; i < arguments.length; i++) {
var fieldName = arguments[i];
var atLeastOne = false;
for (j = 0; j < checkboxes.length; j++) {
if ((checkboxes[j].type == "checkbox" || checkboxes[j].type == "radio")
&& checkboxes[j].name == fieldName
&& checkboxes[j].checked == true)
atLeastOne = true;
}
if (atLeastOne == false) {
alert("Choose one!!!");
return false;
}
}
}
Also for radio buttons, as you can see.
I made an validation method on the action to whom the form is submitted.
deliveryTimesInputList is here the list of integer with the values from the checkboxlist.
#Override
public void validate() {
if(deliveryTimesInputList == null || deliveryTimesInputList.isEmpty()){
addFieldError("deliveryTimesInputList", "Du må velge minst et leveringstidspunkt for dette postnummeret");
}
}
Use the following code for struts2 xml validation .The value of checkbox List is stored as a string.Hence,you can use requiredstring.
<field name="someName">
<field-validator type="requiredstring">
<message>You need to select at least one option</message>
</field-validator>
</field>

Resources