I am trying to customize xml plugin of Sonarqube to check Json syntax. My logic to check Json is working fine when I test it by providing a particular xml file. But when in plugin,it fails.
Here is my code inside the package org.sonar.plugins.xml.checks
#Rule(
key = "JsonCheck",
name = "Json should be in correct format",
description = "This rule is for checking Json",
priority = Priority.CRITICAL,
tags = {"convention"})
#BelongsToProfile(title = CheckRepository.SONAR_WAY_PROFILE_NAME, priority = Priority.CRITICAL)
#SqaleSubCharacteristic(RulesDefinition.SubCharacteristics.READABILITY)
#SqaleConstantRemediation("1min")
#RuleTemplate
public class JsonCheck extends AbstractXmlCheck {
#RuleProperty(key = "Json", description = "This rule is for checking Json", type = "TEXT")
private static final String MESSAGE = "Please provide valid Json";
#Override
public void validate(XmlSourceCode xmlSourceCode) {
setWebSourceCode(xmlSourceCode);
Document document = getWebSourceCode().getDocument(true);
if (document.getDocumentElement() != null) {
validateJson(document.getDocumentElement(),document);
}
}
private void validateJson(Node node, Document document)
{
String JsonString = getJsonString(document);
boolean Json = ValidateJson(JsonString);
if (Json == false) {
createViolation(getWebSourceCode().getLineForNode(node), String.format(MESSAGE));
}
}
private String getJsonString(Document document)
{
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
XPathExpression expr;
try {
expr = xpath.compile("//Payload");
return (String) expr.evaluate(document, XPathConstants.STRING);
} catch (XPathExpressionException e) {
e.printStackTrace();
return "";
}
}
private boolean ValidateJson(String JsonString)
{
boolean bool;
Gson gson = new Gson();
try {
gson.fromJson(JsonString, Object.class);
bool = true;
return bool;
} catch(com.google.gson.JsonSyntaxException ex) {
bool = false;
return bool;
}
}
}
I am not able to understand how this plugin is iterating through all xml files in the project based on which I should change my logic? Or am I missing something here?
Related
I publish some csv input file on a server and it gives me a xml file that looks like this:
<ns0:TransportationEvent xmlns:ns0="http://www.server.com/schemas/TransportationEvent.xsd">
<ns0:deviceId>4567289456</ns0:deviceId>
.....
.....
</ns0:TransportationEvent>
<ns0:TransportationEvent xmlns:ns0="http://www.server.com/schemas/TransportationEvent.xsd">
<ns0:deviceId>7965145741</ns0:deviceId>
.....
.....
</ns0:TransportationEvent>
<ns0:TransportationEvent xmlns:ns0="http://www.server.com/schemas/TransportationEvent.xsd">
<ns0:deviceId>2168744654</ns0:deviceId>
.....
.....
</ns0:TransportationEvent>
The TransportationEvent tag would be added again and again with the updated deviceId in it.
I am retrieving data from this xml using XpathFactory class and NamespaceContext class which is shown as below:
NamespaceContext ctx = new NamespaceContext() {
public String getNamespaceURI(String prefix) {
String uri;
if (prefix.equals("ns0"))
uri = "http://www.server.com/schemas/TransportationEvent.xsd";
else
uri = null;
return uri;
}
public Iterator getPrefixes(String val) {
return null;
}
// Dummy implementation - not used!
public String getPrefix(String uri) {
return null;
}
};
XPathFactory xpathFact = XPathFactory.newInstance();
XPath xpath = xpathFact.newXPath();
xpath.setNamespaceContext(ctx);
String strXpath = "//ns0:TransportationEvent/ns0:deviceId/text()";
String deviceId = xpath.evaluate(strXpath, doc);
The above code gives the value of deviceId as 4567289456. Basically it always take values from the first TransportationEvent tag.
I need to pick data from that "TransportationEvent" tag where the "deviceId" is equal to the deviceId of my choice. Something like this:
String strXpath = "//ns0:TransportationEvent[where ns0:deviceId = " + myDeviceId + "]/ns0:deviceId/text()";
I can perform this by using NodeList class and can iterate through all the "TransportationEvent" tags but then I would not be able to use the Xpath or NamespaceContext implementation. I am finding no connection between the NodeList class and the NamespaceContext class or the Xpath class.
I want to get the value of ctx which has the context of the desired TransportationEvent tag.
I know I am missing something. Could somebody help please?
You could fetch the parent node of the deviceId you are intrested in like this:
//ns0:deviceId[text()='7965145741']/parent::node()
private static final String NS0_NS = "http://www.server.com/schemas/TransportationEvent.xsd";
private static final String NS0 = "ns0";
private static final List<String> prefixes = Arrays.asList(NS0);
public void fromDocument(Document doc) throws XPathExpressionException, TransformerConfigurationException,
TransformerFactoryConfigurationError, TransformerException {
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(new NamespaceContext() {
#Override
public Iterator getPrefixes(String namespaceURI) {
return prefixes.iterator();
}
#Override
public String getPrefix(String namespaceURI) {
String res = namespaceURI.equals(NS0_NS)?NS0:null;
return res;
}
#Override
public String getNamespaceURI(String prefix) {
String res = prefix.equals(NS0)?NS0_NS:null;
return res;
}
});
XPathExpression devex = xpath.compile("//ns0:deviceId[text()='7965145741']/parent::node()");
Node node = (Node) devex.evaluate(doc,XPathConstants.NODE);
Transformer xformer = TransformerFactory.newInstance().newTransformer();
xformer.transform(new DOMSource(node),new StreamResult(System.out));
}
that's the output:
<ns0:TransportationEvent xmlns:ns0="http://www.server.com/schemas/TransportationEvent.xsd">
<ns0:deviceId>7965145741</ns0:deviceId>
</ns0:TransportationEvent>
I've a requirement. lets say I have a JSON file as shown below.
{
"orgId": 27,
"orgType":"MotorBikes",
"orgName":"ROYAL Enfield",
"orgAddress":"Express Estate",
"orgCity":"Chennai",
"orgState":"TamilNadu"
}
So I need to do two validations. one is checking all the json fields and return true or false and second one should have methods to validate partial response like for example: isExists(jsonObject, "orgType":"MotorBikes") should return true. This comparison should be done using jax-rs libraries. So if anybody who is familiar with this please tell me. This would help me a lot.
Package javax.json should be enough.
import javax.json.JsonObject;
public static void main(String[] args){
JsonObject jsonObj = /* your json */;
boolean all = checkAll(jsonObj,new String[]{"orgId","orgType","orgName","orgAddress","orgCity","orgState"});
boolean one = isExists(jsonObj,"orgType","MotorBikes");
}
private boolean checkAll(JsonObject jsonObj, String[] keys) {
for(String key: keys) {
if(jsonObj.get(key)==null) return false;
}
return true;
}
private boolean isExists(JsonObject jsonObj, String key, String value) {
return (jsonObj.get(key)!=null && jsonObj.get(key).equals(value));
}
UPDATE:
A more focused answer using org.json library which is in your dependency and is a JSON library, not JAX-RS.
#Test
public void test() throws FileNotFoundException{
String jsonAsString = when().get("/your.get").then().contentType(ContentType.JSON).extract().response().asString();
JSONObject jsonFromResponse = new JSONObject(jsonAsString);
File file = /** Load your file ***/
FileInputStream is = new FileInputStream(file);
JSONTokener tokener = new JSONTokener(is);
while(tokener.more()) { // Iterate through Json file
JSONObject obj = (JSONObject) tokener.nextValue();
for(String key: obj.keySet()) {
boolean valid = validateField(key, jsonFromResponse);
System.out.println("'"+key+"' field "+(valid?"not ":"")+"present");
}
}
boolean v = validateValue(jsonFromResponse, "orgName", "ROYAL Enfield");
System.out.println("Validation: "+v);
}
private boolean validateValue(JSONObject json, String key, String value) {
if(validateField(key,json))
return value.equals(json.getString(key));
return false;
}
private boolean validateField(String key, JSONObject jsonFromResponse) {
Object valueFromResponse = null;
try {
valueFromResponse = jsonFromResponse.get(key);
}
catch(JSONException e){
valueFromResponse = null;
}
return valueFromResponse!=null;
}
The context is as follows:
I've got objects that represent Tweets (from Twitter). Each object has an id, a date and the id of the original tweet (if there was one).
I receive a file of tweets (where each tweet is in the format of 05/04/2014 12:00:00, tweetID, originalID and is in its' own line) and I want to save them as an XML file where each field has its' own tag.
I want to then be able to read the file and return a list of Tweet objects corresponding to the Tweets from the XML file.
After writing the XML parser that does this I want to test that it works correctly. I've got no idea how to test this.
The XML Parser:
public class TweetToXMLConverter implements TweetImporterExporter {
//there is a single file used for the tweets database
static final String xmlPath = "src/main/resources/tweetsDataBase.xml";
//some "defines", as we like to call them ;)
static final String DB_HEADER = "tweetDataBase";
static final String TWEET_HEADER = "tweet";
static final String TWEET_ID_FIELD = "id";
static final String TWEET_ORIGIN_ID_FIELD = "original tweet";
static final String TWEET_DATE_FIELD = "tweet date";
static File xmlFile;
static boolean initialized = false;
#Override
public void createDB() {
try {
Element tweetDB = new Element(DB_HEADER);
Document doc = new Document(tweetDB);
doc.setRootElement(tweetDB);
XMLOutputter xmlOutput = new XMLOutputter();
// display nice nice? WTF does that chinese whacko want?
xmlOutput.setFormat(Format.getPrettyFormat());
xmlOutput.output(doc, new FileWriter(xmlPath));
xmlFile = new File(xmlPath);
initialized = true;
} catch (IOException io) {
System.out.println(io.getMessage());
}
}
#Override
public void addTweet(Tweet tweet) {
if (!initialized) {
//TODO throw an exception? should not come to pass!
return;
}
SAXBuilder builder = new SAXBuilder();
try {
Document document = (Document) builder.build(xmlFile);
Element newTweet = new Element(TWEET_HEADER);
newTweet.setAttribute(new Attribute(TWEET_ID_FIELD, tweet.getTweetID()));
newTweet.setAttribute(new Attribute(TWEET_DATE_FIELD, tweet.getDate().toString()));
if (tweet.isRetweet())
newTweet.addContent(new Element(TWEET_ORIGIN_ID_FIELD).setText(tweet.getOriginalTweet()));
document.getRootElement().addContent(newTweet);
} catch (IOException io) {
System.out.println(io.getMessage());
} catch (JDOMException jdomex) {
System.out.println(jdomex.getMessage());
}
}
//break glass in case of emergency
#Override
public void addListOfTweets(List<Tweet> list) {
for (Tweet t : list) {
addTweet(t);
}
}
#Override
public List<Tweet> getListOfTweets() {
if (!initialized) {
//TODO throw an exception? should not come to pass!
return null;
}
try {
SAXBuilder builder = new SAXBuilder();
Document document;
document = (Document) builder.build(xmlFile);
List<Tweet> $ = new ArrayList<Tweet>();
for (Object o : document.getRootElement().getChildren(TWEET_HEADER)) {
Element rawTweet = (Element) o;
String id = rawTweet.getAttributeValue(TWEET_ID_FIELD);
String original = rawTweet.getChildText(TWEET_ORIGIN_ID_FIELD);
Date date = new Date(rawTweet.getAttributeValue(TWEET_DATE_FIELD));
$.add(new Tweet(id, original, date));
}
return $;
} catch (JDOMException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
Some usage:
private TweetImporterExporter converter;
List<Tweet> tweetList = converter.getListOfTweets();
for (String tweetString : lines)
converter.addTweet(new Tweet(tweetString));
How can I make sure the the XML file I read (that contains tweets) corresponds to the file I receive (in the form stated above)?
How can I make sure the tweets I add to the file correspond to the ones I tried to add?
Assuming that you have the following model:
public class Tweet {
private Long id;
private Date date;
private Long originalTweetid;
//getters and seters
}
The process would be the following:
create an isntance of TweetToXMLConverter
create a list of Tweet instances that you expect to receive after parsing the file
feed the converter the list you generated
compare the list received by parsing the list and the list you initiated at the start of the test
public class MainTest {
private TweetToXMLConverter converter;
private List<Tweet> tweets;
#Before
public void setup() {
Tweet tweet = new Tweet(1, "05/04/2014 12:00:00", 2);
Tweet tweet2 = new Tweet(2, "06/04/2014 12:00:00", 1);
Tweet tweet3 = new Tweet(3, "07/04/2014 12:00:00", 2);
tweets.add(tweet);
tweets.add(tweet2);
tweets.add(tweet3);
converter = new TweetToXMLConverter();
converter.addListOfTweets(tweets);
}
#Test
public void testParse() {
List<Tweet> parsedTweets = converter.getListOfTweets();
Assert.assertEquals(parsedTweets.size(), tweets.size());
for (int i=0; i<parsedTweets.size(); i++) {
//assuming that both lists are sorted
Assert.assertEquals(parsedTweets.get(i), tweets.get(i));
};
}
}
I am using JUnit for the actual testing.
I;m using XPath to parse XML document returned by a URL, when i run my code with given inputs it works but when giving it inputs as a user input it throws an exception.
The Code:
class{
private String generalQuery = "//#*";
method(){
System.out.println("Enter URL");
url = scan.nextLine();
URL oracle = new URL(url);
InputStream is = oracle.openStream();
org.w3c.dom.Document doc = null;
DocumentBuilderFactory domFactory;
DocumentBuilder builder;
try {
domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
builder = domFactory.newDocumentBuilder();
doc = builder.parse(is);
} catch (Exception ex) {
System.err.println("unable to load XML: " + ex);
}
Map <String, String> params = new HashMap<String, String> ();
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
xpath.setNamespaceContext(new NameSpaces(doc));
XPathExpression expr = xpath.compile(generalQuery);
Object result = expr.evaluate(doc, XPathConstants.NODESET); // exception thrown here
NodeList nl = (NodeList) result;
for (int i = 0 ; i < nl.getLength() ; i++){
Node n = (Node)nl.item(i);
params.put(n.getNodeName(), n.getNodeValue());
}
return params;
}
}
The Exception:
javax.xml.transform.TransformerException: Unable to evaluate expression using this context
The class NameSpaces :
import java.util.Iterator;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import org.w3c.dom.Document;
public class NameSpaces implements NamespaceContext {
private Document sourceDocument;
public NameSpaces(Document document) {
sourceDocument = document;
}
#Override
public String getNamespaceURI(String prefix) {
if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
return sourceDocument.lookupNamespaceURI(null);
} else {
return sourceDocument.lookupNamespaceURI(prefix);
}
}
#Override
public String getPrefix(String namespaceURI) {
return sourceDocument.lookupPrefix(namespaceURI);
}
#Override
public Iterator<String> getPrefixes(String namespaceURI) {
return null;
}
}
The exception "Unable to evaluate expression using this context" may also result from a null document when trying to evaluate an XPath expression. (I had the same error and it took me a while to figure out I did not initialize my document properly).
In your code you have
try {
// load document
}
catch (Exception ex) {
System.err.println("unable to load XML: " + ex);
}
// happily continue
This is a call for trouble. If an exception happens during initialization you should STOP right there and you should not continue. If you have absolutely no idea how to handle the error, use catch(Exception e) { throw new Error(e); }. This will cause exceptions to bubble up and hopefully be handled by the default exception handler which prints a stack trace and exits.
As the reader of your question I don't even know where the exception was thrown. You should provide this information. Note that you can also use someException.printStackTrace(); to get the stack trace which points you to the correct line.
What you seem to be missing is a NameSpaceContext that you can implement yourself.
Also see this thread: NamespaceContext and using namespaces with XPath
Example:
class NamespaceResolver implements NamespaceContext {
private final Document document;
public NamespaceResolver(Document document) {
this.document = document;
}
public String getNamespaceURI(String prefix) {
if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
return document.lookupNamespaceURI(null);
} else {
return document.lookupNamespaceURI(prefix);
}
}
public String getPrefix(String namespaceURI) {
return document.lookupPrefix(namespaceURI);
}
#SuppressWarnings("rawtypes")
public Iterator getPrefixes(String namespaceURI) {
// not implemented
return null;
}
}
Then you initiate the XPath instance like this:
getXPath().setNamespaceContext(new NamespaceResolver(doc));
In my case this was not due to a null document, but due to an empty document with no root element. Appending the latter solved the issue.
I use Simple XML (simple-xml-2.6.2.jar) to parse xml file like:
<?xml version="1.0" encoding="UTF-8" ?>
<orderList>
<order id="1">
<name>NAME1</name>
</order>
<order id="2">
<name>NAME2</name>
</order>
</orderList>
The root Element contains subElements.
I wanna it be ArrayList, How to do it?
Here's a possible solution, hope it helps you:
Annotations of Order class:
#Root(name="order")
public class Order
{
#Attribute(name="id", required=true)
private int id;
#Element(name="name", required=true)
private String name;
public Order(int id, String name)
{
this.id = id;
this.name = name;
}
public Order() { }
// Getter / Setter
}
Example class, containing the list:
#Root(name="elementList")
public class Example
{
#ElementList(required=true, inline=true)
private List<Order> list = new ArrayList<>();
// ...
}
And here's some code for reading your code:
Serializer ser = new Persister();
Example example = ser.read(Example.class, file); // file = your xml file
// 'list' now contains all your Orders
List is an interface, ArrayList is one of its implementation, like:
List<Order> l = new ArrayList<Order>()
So if you have a List , you basically have what you want.
If I've interpreted your question correctly, you want a list of orders. I've not tested this for your setup but this works for me for a similar xml structure (assumes you have a custom class called Order):
List<Order> orders = new ArrayList<Order>();
XMLDOMParser parser = new XMLDOMParser();
AssetManager manager = context.getAssets();
InputStream stream;
try {
stream = manager.open("test.xml"); //need full path to your file here - mine is stored in assets folder
Document doc = parser.getDocument(stream);
}catch(IOException ex){
System.out.printf("Error reading xml file %s\n", ex.getMessage());
}
NodeList nodeList = doc.getElementsByTagName("order");
for (int i = 0; i < nodeList.getLength(); i++) {
Element e = (Element) nodeList.item(i); //each order item
Node order=nodeList.item(i);
subList = order.getFirstChild(); //get the name child node
orders.add(order);
}
//XMLDOMParser Class
public class XMLDOMParser {
//Returns the entire XML document
public Document getDocument(InputStream inputStream) {
Document document = null;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder db = factory.newDocumentBuilder();
InputSource inputSource = new InputSource(inputStream);
document = db.parse(inputSource);
} catch (ParserConfigurationException e) {
Log.e("Error: ", e.getMessage());
return null;
} catch (SAXException e) {
Log.e("Error: ", e.getMessage());
return null;
} catch (IOException e) {
Log.e("Error: ", e.getMessage());
return null;
}
return document;
}
/*
* I take a XML element and the tag name, look for the tag and get
* the text content i.e for <employee><name>Kumar</name></employee>
* XML snippet if the Element points to employee node and tagName
* is name I will return Kumar. Calls the private method
* getTextNodeValue(node) which returns the text value, say in our
* example Kumar. */
public String getValue(Element item, String name) {
NodeList nodes = item.getElementsByTagName(name);
return this.getTextNodeValue(nodes.item(0));
}
private final String getTextNodeValue(Node node) {
Node child;
if (node != null) {
if (node.hasChildNodes()) {
child = node.getFirstChild();
while(child != null) {
if (child.getNodeType() == Node.TEXT_NODE) {
return child.getNodeValue();
}
child = child.getNextSibling();
}
}
}
return "";
}
}