I write an API using springMVC.It's a simple API, I just use it to test JsonProvider.
#ResponseBody
#RequestMapping(value = "/api/test", method = RequestMethod.GET)
public TestClass test(final HttpServletRequest request,
final HttpServletResponse response){
return new TestClass("cc");
}
class TestClass{
public TestClass(){
}
public TestClass(final String name) {
super();
this.name = name;
}
private String name;
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
}
The API simply returns
But JsonProvider just throws a compile error.
Severity Code Description Project File Line
Error The type provider 'ProviderImplementation.JsonProvider' reported an error: Cannot read sample JSON from 'http://localhost/api/test': Invalid JSON starting at character 0, snippet =
----
"{\"name\":
-----
json =
------
"{\"name\":\"cc\"}"
------- JsonProcess c:\users\xx\documents\visual studio 2015\Projects\JsonProcess\JsonProcess\Program.fs 8
The F# code:
open FSharp.Data
[<Literal>]
let jsonValue = """
{"name":"cc"}
"""
type JsonData = JsonProvider<"http://localhost/api/test">
[<EntryPoint>]
let main argv =
0 // return an integer exit code
Use the String literal jsonValue as sample is ok.type JsonData = JsonProvider<jsonValue>
I checked the FSharp.Data source code (its the function asyncRead) to see how they download the JSON. It basically boils down to this:
let readString =
async {
let contentTypes = [ HttpContentTypes.Json ]
let headers = [
HttpRequestHeaders.UserAgent ("F# Data JSON Type Provider")
HttpRequestHeaders.Accept (String.concat ", " contentTypes)
]
let! text = Http.AsyncRequestString("http://www.kujiale.com/api/askinvitesearch?query=cc", headers = headers)
return text
}
If one runs this code against the url http://www.kujiale.com/api/askinvitesearch?query=cc we see something interesting about what's returned:
"[{\"linkToIdeaBook\":\"/u/3FO4K4UR89F1/huabao\",\"linkToDesi
Note that the content starts with " and that the "strings" are "escaped" with \. So it seems the JSON document is returned as an escaped string. According to json.org the root object must be either an object or array so the parser fails at character 0.
If one switches to contentType HttpContentTypes.Text it starts like this:
[{"linkToIdeaBook":"/u/3FO4K4UR89F1/huabao","linkToDesignCollect":"/u
Which actually turns out to be a valid JSON object.
To me it seems somewhat odd that if you ask for content with content type JSON you get an escaped string but that seems to be the root cause of the failure.
How to resolve it is more difficult to say. One way forward would be a PR to FSharp.Data to allow users to specify the content type used to download content.
Related
I am trying to implement custom function using Saxon as defined here-> https://specifications.xbrl.org/registries/functions-registry-1.0/80132%20xfi.identifier/80132%20xfi.identifier%20function.html
public class IdentifierFunction implements ExtensionFunction {
public QName getName() {
return new QName("http://www.xbrl.org/2005/function/instance", "identifier");
}
public SequenceType getResultType() {
return SequenceType.makeSequenceType(ItemType.STRING, OccurrenceIndicator.ONE);
}
public net.sf.saxon.s9api.SequenceType[] getArgumentTypes() {
return new SequenceType[] { SequenceType.makeSequenceType(ItemType.STRING, OccurrenceIndicator.ONE) };
}
public XdmValue call(XdmValue[] arguments) throws SaxonApiException {
String arg = ((XdmAtomicValue) arguments[0].itemAt(0)).getStringValue();
String newExpression="(//xbrli:xbrl/xbrli:context[#id=("+arg+"/#contextRef"+")])[1]/xbrli:entity/xbrli:identifier";
String nodeString=this.getxPathResolver().resolveNode(this.getXbrl(),newExpression);
return new XdmAtomicValue(nodeString);
}
}
resolveNode() is above code is implemented as follows
public String resolveNode(byte[] xbrlBytes, String expressionValue) {
// 1. Instantiate an XPathFactory.
javax.xml.xpath.XPathFactory factory = new XPathFactoryImpl();
// 2. Use the XPathFactory to create a new XPath object
javax.xml.xpath.XPath xpath = factory.newXPath();
NamespaceContext ctx = new NamespaceContext() {
#Override
public String getNamespaceURI(String aPrefix) {
if (aPrefix.equals("xfi"))
return "http://www.xbrl.org/2005/function/instance";
else if (aPrefix.equals("xs"))
return "http://www.w3.org/2001/XMLSchema";
else if (aPrefix.equals("xbrli"))
return "http://www.xbrl.org/2003/instance";
else
return null;
}
#Override
public Iterator getPrefixes(String val) {
throw new UnsupportedOperationException();
}
#Override
public String getPrefix(String uri) {
throw new UnsupportedOperationException();
}
};
xpath.setNamespaceContext(ctx);
try {
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder();
Document someXML = documentBuilder.parse(new InputSource(new StringReader(new String(xbrlBytes))));
// 3. Compile an XPath string into an XPathExpression
javax.xml.xpath.XPathExpression expression = xpath.compile(expressionValue);
Object result = expression.evaluate(someXML, XPathConstants.NODE);
// 4. Evaluate the XPath expression on an input document
Node nodes = (Node) result;
return nodeToString(nodes);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
When I evaluate xfi:identifier(args) , i get String like below:
<xbrli:identifier xmlns:xbrli="http://www.xbrl.org/2003/instance"
xmlns:iso4217="http://www.xbrl.org/2003/iso4217"
xmlns:jenv-bw2-dim="http://www.nltaxonomie.nl/nt13/jenv/20181212/dictionary/jenv-bw2-axes"
xmlns:jenv-bw2-dm="http://www.nltaxonomie.nl/nt13/jenv/20181212/dictionary/jenv-bw2-domains"
xmlns:jenv-bw2-i="http://www.nltaxonomie.nl/nt13/jenv/20181212/dictionary/jenv-bw2-data"
xmlns:kvk-i="http://www.nltaxonomie.nl/nt13/kvk/20181212/dictionary/kvk-data"
xmlns:link="http://www.xbrl.org/2003/linkbase"
xmlns:nl-cd="http://www.nltaxonomie.nl/nt13/sbr/20180301/dictionary/nl-common-data"
xmlns:rj-i="http://www.nltaxonomie.nl/nt13/rj/20181212/dictionary/rj-data"
xmlns:rj-t="http://www.nltaxonomie.nl/nt13/rj/20181212/dictionary/rj-tuples"
xmlns:xbrldi="http://xbrl.org/2006/xbrldi"
xmlns:xlink="http://www.w3.org/1999/xlink"
scheme="http://www.kvk.nl/kvk-id">62394207</xbrli:identifier>
However, I want to evaluate function number(xfi:identifier(args))
This results in NaN which is obvious because complete node string cannot be converted to number. I think, I need to change my function so that it returns Node. However, I am not sure how to do that. I tried google and also looked at Saxon documentation, but no luck yet.
Can someone help me? Basically, custom function should return an element node as per definition. and when I use number(xfi:identifier) it should give me 62394207 in this case.
regards,
Venky
Firstly, the XBRL spec for the function seems to imply that the function expects a node as argument and returns a node as its result, but in your implementation getArgumentTypes() and getResultType() define the type as xs:string - so this needs to change.
And the function should return an XdmNode, which is a subclass of XdmValue.
Next, it's very inefficient to be creating a DocumentBuilderFactory and XPathFactory, constructing an XML document tree, and compiling an XPath expression, every time your function is executed. I strongly suspect none of this is necessary.
Instead of having this.getXbrl() return a raw lexical document as byte[], have it return a prebuilt XdmNode representing the document tree. And then I would suggest that rather than selecting within that tree using XPath, you use Saxon's linq-like navigation API. If this XdmNode is in variable "root", then the XPath expression
//xbrli:xbrl/xbrli:context[#id=("+arg+"/#contextRef"+")
translates into something like
root.select(descendant("xbrl").then(child("context)).where(attributeEq("id", arg))
(except that I'm not quite sure what you're passing as arg to make your XPath expression make sense).
But you can use XPath if you prefer; just use Saxon's s9api interfaces for XPath and make sure the XPath expression is only compiled once and used repeatedly. It's straightforward then to get an XdmNode as the result of your XPath expression, which can be returned directly as the result of your extension function.
There is nameof operator in C#, it allows to get property name at compile time:
var name = nameof(User.email);
Console.WriteLine(name);
//Prints: email
It is not possible to use reflection in flutter and I do not want to hardcode names of properties i.e. to be used for querying SQLite tables. Is there any workaround?
***Currently I'm using built_value library.
For the archives, I guess, this isn't possible as Dart doesn't store the names of variables after compiling, and as you mentioned, Flutter doesn't support reflection.
But you can still hardcode responsibly by grouping your properties as part of the object that they belong to, like with JSON:
class User {
final String email;
final String name;
const User({required this.email, required this.name});
Map toJson() => {
"email": email,
"name": name,
};
}
Instead of remembering to type out "email" and "name" whenever you use User, just call User.toJson(). Then, when you want to rename your variables, you can use your IDE's "rename all", or just skim over your User class to quickly change all of the names without missing any.
I'm currently monitoring the progress on the dart:mirrors package, which offers some neat reflective properties and methods, though, I hadn't found a simple way to just get the name of a symbol like nameof() does.
Example:
import 'dart:mirrors';
class User {
final String email;
final String name;
const User({required this.email, required this.name});
}
void main() {
reflectClass(User).declarations.forEach((key, value) {
print(value.simpleName);
});
}
Output:
Symbol("email")
Symbol("name")
Symbol("User")
These are of type Symbol.
More here: https://api.dart.dev/stable/2.4.0/dart-mirrors/dart-mirrors-library.html
So, until they develop a nameof, I've created an extension on symbol:
extension SymbolExtensions on Symbol {
String get nameof =>
RegExp(r'"(.*?)"').firstMatch(toString())!.group(1).toString();
}
So, you could do:
print(reflectClass(User)
.declarations[#email)]!
.simpleName
.nameof);
Output:
email
It's a start. Dart is still growing.
You can use code generation.
The basic idea is to create a nameof annotation class and mark parts of your code with it. You also need to create a code generator that handles your annotated code. Look at the json_serializable package for an example and create your own code generator.
If you do not want to create your own generator, use a ready-made package nameof: https://pub.dev/packages/nameof
Short how-to with this package.
Mark your class with nameof annotation.
#nameof
class Car {
final double price;
final double weigth;
final int year;
final String model;
Car(this.price, this.weigth, this.year, this.model);
Car.sedan(double price, double weigth, int year)
: this(price, weigth, year, 'Sedan');
}
Run the code generator.
flutter pub run build_runner build
Then use the generated class, which will look something like this.
/// Container for names of elements belonging to the [Car] class
abstract class NameofCar {
static const String className = 'Car';
static const String constructor = '';
static const String constructorSedan = 'sedan';
static const String fieldPrice = 'price';
static const String fieldWeigth = 'weigth';
static const String fieldYear = 'year';
static const String fieldModel = 'model';
}
You can implement your own nameOf function:
String? nameOf(dynamic o) {
if (o == null) return "null";
try {
if (o is List) {
var first = o.length > 0 ? o[0] : null;
if (first != null) {
var elementType = nameOf(first)!;
Log.debug("nameOf: List<$elementType>");
if (!isMinified(elementType))
return "List<$elementType>";
}
} else {
Function? getTypeName = o.getTypeName;
if (getTypeName != null) return getTypeName();
}
} catch (e) {
Log.debug("ignored nameOf error: $e, falling back to o.runtimeType: ${o.runtimeType}");
}
return o.runtimeType.toString();
}
bool isMinified(String type) => type.startsWith("minified:");
public class ChemDB : MonoBehaviour
{
private int i;
void Start ()
{
string[] lines = System.IO.File.ReadAllLines("Assets/Scripts/Data/Database.txt");
int perioada=0,grupa=0,nrAt=0,masa=0,valenta=0,a=0,b=0,c=0,d=0,e=0,f=0,g=0;
string Nume,Simbol,Tip,Stare;
for(i=1;i<=118;i++)
{
Int32.Parse(lines[(i-1)*16],perioada);
Int32.Parse(lines[1+(i-1)*16],grupa);
Int32.Parse(lines[2+(i-1)*16],nrAt);
Nume=lines[3+(i-1)*16];
Simbol=lines[4+(i-1)*16];
Int32.Parse(lines[5+(i-1)*16],masa);
Int32.Parse(lines[6+(i-1)*16],valenta);
Tip=lines[7+(i-1)*16];
Stare=lines[8+(i-1)*16];
Int32.Parse(lines[9+(i-1)*16],a);
Int32.Parse(lines[10+(i-1)*16],b);
Int32.Parse(lines[11+(i-1)*16],c);
Int32.Parse(lines[12+(i-1)*16],d);
Int32.Parse(lines[13+(i-1)*16],e);
Int32.Parse(lines[14+(i-1)*16],f);
Int32.Parse(lines[15+(i-1)*16],g);
}
}
}
I'm using Unity C#.I get thhis error "The best overloaded method match for `int.Parse(string, System.IFormatProvider)' has some invalid arguments." and i don't understand what i'm doing wrong.
Int32.Parse taskes the string as the first parameters, and returns the number as an int.
You are passing the variable to store the int as the second parameter like this:
Int32.Parse(lines[(i-1)*16],perioada);
It should be used like this:
perioada = Int32.Parse(lines[(i-1)*16]);
Thats why you are getting the error, because the second optional parameter is used to define the format of the string passed in the first parameter. But since you are using an int, the types don't match.
I have seen Grok being very strong and lethal in parsing the log data. I wanted to use Grok for log parsing in our application, which is in java.. How can i connect/work with Grok from Java.?
Try downloading java-grok from GitHub: https://github.com/NFLabs/java-grok
You can test patterns using the Grok Debugger: http://grokdebug.herokuapp.com/
Check out this Java library
https://github.com/aicer/grok
You can include it in your project as a maven dependency
<dependency>
<groupId>org.aicer.grok</groupId>
<artifactId>grok</artifactId>
<version>0.9.0</version>
</dependency>
It comes with pre-defined patterns and you can also add yours.
The named patterns are extracted and the results are available in a map with the groups names as the keys and the retrieved values are mapped to these keys.
final GrokDictionary dictionary = new GrokDictionary();
// Load the built-in dictionaries
dictionary.addBuiltInDictionaries();
// Add custom pattern
dictionary.addDictionary(new File(patternDirectoryOrFilePath));
// Resolve all expressions loaded
dictionary.bind();
This next examples adds string patterns directly to the dictionary without using a file
final GrokDictionary dictionary = new GrokDictionary();
// Load the built-in dictionaries
dictionary.addBuiltInDictionaries();
// Add custom pattern directly
dictionary.addDictionary(new StringReader("DOMAINTLD [a-zA-Z]+"));
dictionary.addDictionary(new StringReader("EMAIL %{NOTSPACE}#%{WORD}\.%{DOMAINTLD}"));
// Resolve all expressions loaded
dictionary.bind();
Here is a complete example of how to use the library
public final class GrokStage {
private static final void displayResults(final Map<String, String> results) {
if (results != null) {
for(Map.Entry<String, String> entry : results.entrySet()) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
}
}
public static void main(String[] args) {
final String rawDataLine1 = "1234567 - israel.ekpo#massivelogdata.net cc55ZZ35 1789 Hello Grok";
final String rawDataLine2 = "98AA541 - israel-ekpo#israelekpo.com mmddgg22 8800 Hello Grok";
final String rawDataLine3 = "55BB778 - ekpo.israel#example.net secret123 4439 Valid Data Stream";
final String expression = "%{EMAIL:username} %{USERNAME:password} %{INT:yearOfBirth}";
final GrokDictionary dictionary = new GrokDictionary();
// Load the built-in dictionaries
dictionary.addBuiltInDictionaries();
// Resolve all expressions loaded
dictionary.bind();
// Take a look at how many expressions have been loaded
System.out.println("Dictionary Size: " + dictionary.getDictionarySize());
Grok compiledPattern = dictionary.compileExpression(expression);
displayResults(compiledPattern.extractNamedGroups(rawDataLine1));
displayResults(compiledPattern.extractNamedGroups(rawDataLine2));
displayResults(compiledPattern.extractNamedGroups(rawDataLine3));
}
}
I have the following classes
#XmlRootElement(name = "ExecutionRequest")
#XmlAccessorType(XmlAccessType.FIELD)
public class ExecutionRequest {
#XmlElement(name="Command")
private String command;
#XmlElementWrapper(name="ExecutionParameters")
#XmlElement(name="ExecutionParameter")
private ArrayList<ExecutionParameter> ExecutionParameters;
}
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class ExecutionParameter {
#XmlElement(name = "Key")
private String key;
#XmlElement(name = "Value")
private String value;
}
and when I marshall the ExecutionRequest object, I get the following XML -
<ExecutionRequest>
<Command>RetrieveHeader</Command>
<ExecutionParameters>
<ExecutionParameter>
<Key>tid</Key>
<Value>ASTLGA-ALTE010220101</Value>
</ExecutionParameter>
<ExecutionParameter>
<Key>ctag</Key>
<Value>dq</Value>
</ExecutionParameter>
</ExecutionParameters>
</ExecutionRequest>
It is working fine as per JAXB binding.
But I want the XML to have all key value collection within one ExecutionParameter like -
<ExecutionRequest>
<Command>RetrieveHeader</Command>
<ExecutionParameters>
<ExecutionParameter>
<Key>tid</Key>
<Value>ASTLGA-ALTE010220101</Value>
<Key>ctag</Key>
<Value>dq</Value>
</ExecutionParameter>
</ExecutionParameters>
</ExecutionRequest>
Is there any way to obtain xml like this by changing annotation.
Let me know in case of clarifications.
Thanks in advance.
There isn't metadata for that. You could get a compact XML representation (that is easily parseable) by mapping key and value with #XmlAttribute.
<ExecutionParameters>
<ExecutionParameter Key="a" Value="b"/>
<ExecutionParameter Key="c" Value="d"/>
</ExecutionParameters>
UPDATE
If you have to support this XML format, then you could use JAXB with XSLT to get the desired result:
// Create Transformer
TransformerFactory tf = TransformerFactory.newInstance();
StreamSource xslt = new StreamSource(
"src/example/stylesheet.xsl");
Transformer transformer = tf.newTransformer(xslt);
// Source
JAXBContext jc = JAXBContext.newInstance(ExecutionRequest.class);
JAXBSource source = new JAXBSource(jc, request);
// Result
StreamResult result = new StreamResult(System.out);
// Transform
transformer.transform(source, result);
For More Information
http://blog.bdoughan.com/2012/11/using-jaxb-with-xslt-to-produce-html.html