Hi I\'m wondering what the best approach would be to parse an OData $filter string in C#, for example
/API/organisations?$filter=\"name eq \'Facebook\' or name eq \'
I think you are supposed to travserse the AST with the interface provided using the visitor pattern.
Consider you have this class that represents a filter
public class FilterValue
{
public string ComparisonOperator { get; set; }
public string Value { get; set; }
public string FieldName { get; set; }
public string LogicalOperator { get; set; }
}
So, how do we "extract" the filters that comes with the OData parameters to your class?
Well the FilterClause object have an Expression property which is a SingleValueNode wich inherits from a QueryNode. The QueryNode have the Accept method who takes a QueryNodeVisitor.
public virtual T Accept(QueryNodeVisitor visitor);
Right, so you must implement your own QueryNodeVisitor and do your stuff. Below is a non finished example (I dont override all possible visitors).
public class MyVisitor : QueryNodeVisitor
where TSource: class
{
List filterValueList = new List();
FilterValue current = new FilterValue();
public override TSource Visit(BinaryOperatorNode nodeIn)
{
if(nodeIn.OperatorKind == Microsoft.Data.OData.Query.BinaryOperatorKind.And
|| nodeIn.OperatorKind == Microsoft.Data.OData.Query.BinaryOperatorKind.Or)
{
current.LogicalOperator = nodeIn.OperatorKind.ToString();
}
else
{
current.ComparisonOperator = nodeIn.OperatorKind.ToString();
}
nodeIn.Right.Accept(this);
nodeIn.Left.Accept(this);
return null;
}
public override TSource Visit(SingleValuePropertyAccessNode nodeIn)
{
current.FieldName = nodeIn.Property.Name;
//We are finished, add current to collection.
filterValueList.Add(current);
//Reset current
current = new FilterValue();
return null;
}
public override TSource Visit(ConstantNode nodeIn)
{
current.Value = nodeIn.LiteralText;
return null;
}
}
Then, fire away :)
MyVisitor
When it has traversed the tree your
visitor.filterValueList
should contain the filters in your desired format. Im sure more work is needed but if you can get this rolling I think you can figure it out.