Specify XML path in dom4j - java

I want to parse a large xml file using dom4j. I'm using the dom4j's feature that you can register event handlers for path expressions for ignoring the elements I don't care about. The feature is explained here: http://dom4j.sourceforge.net/dom4j-1.6.1/faq.html#large-doc.
I quote from there:
"These handlers will then be called on the start and end of each path registered against a particular handler. When the start tag of a path is found, the onStart method of the handler registered to the path is called. When the end tag of a path if found, the onEnd method of the handler registered to that path is called.
The onStart and onEnd methods are passed an instance of an ElementPath, which can be used to retrieve the current Element for the given path. If the handler wishes to "prune" the tree being built in order to save memory use, it can simply call the detach() method of the current Element being processed in the handlers onEnd() method."
My problem is that I don't know what path should I give so that all the children of the root node to be handled by the 2 methods.
My xml file is something like:
<root .....>
<chef name="" ..../>
<chef name="" ..../>
<recipe name = .... />
<recipe name...../>
....
If I would like to handle chef elements than the path would be /root/chef.
For recipe elements the path would be /root/recipe.
But what is the path that should be given to the dom4j so that it will handle (in the onStart(), onEnd()) both chef and recipe elements?
Thanks a lot!

Instead of calling the addHandler() method, call the setDefaultHandler() and use it like this:
SAXReader reader = new SAXReader();
reader.setDefaultHandler(
new ElementHandler() {
public void onStart(ElementPath path) {
// If needed, similar to onEnd, but don't detach.
}
public void onEnd(ElementPath path) {
Element parent = path.getCurrent().getParent();
if(parent != null && "/root".equals(parent.getPath()) {
// Do whatever
}
path.getCurrent().detach();
}
}
);

Try //root/child::* or //root/descendant::* depending on what level of depth you want.
see w3schools for more on the available xpath axes

Related

adding function to jsonjava object and calling it from xpages control

I am trying to add a function to a JSONJavaObject and calling it from a control on an xpage.
so far I have:
json = (JsonJavaObject) JsonParser.fromJson(factory, colJson);
String func = "function () { alert('you clicked?'); }";
json.put("onClick", new JsonReference(func) );
In the first line I add key-value pairs from a column in a Notes view.
In the second line I define the function as a string.
In the last line I place the converted string as function in the jsonjava object.
I read about this in the following blog post:
http://camerongregor.com/2016/01/19/doublequoteavoidance/
In the next step I bind the function to e.g. a button control as followed:
<xp:button value="Label" id="button1">
<xp:eventHandler event="onclick" submit="false">
<xp:this.script><![CDATA[obj.onClick]]></xp:this.script>
</xp:eventHandler>
</xp:button>
obj is the respresentation of the JSONJava object in SSJS.
But without success. Anyone know how I can call the function in the object?
I hope I will make sense here, let me know if anything to clarify.
If you are simply trying to dynamically output the client side script of a button event, then you don't need to use JsonReference at all. You can just use a String.
In my blog article I might not have make it clear why I needed to use JsonReference. I was using it in the process of rendering a custom UIComponent, part of this process required generating a Json object client side. To do this I created the JsonJavaObject as you did and then asked it to be turned into a string with the 'toJson' method. My problem was that when I asked the whole object to become a string, every property of that object that was a String, would begin and end with a double quote. I needed to ensure that the properties which were intended to be functions did not begin and end with "". By using the JsonReference the JsonGenerator became aware of my intention not to include these double quotes.
In your case, it looks as though you are just trying to dynamically determine what happens with onClick. To do this you could simply use a String instead of the JsonReference. The inclusion of the 'function() {}' is unnecessary as this will be generated when the event handler is rendered at the end of the page.
For Example here would be the Json Java Object
JsonJavaObject obj = new JsonJavaObject();
String func = " alert('you clicked?'); ";
obj.put("onClick", func);
return obj;
And here would be the button:
<xp:button id="button1" value="Alert Me">
<xp:eventHandler event="onclick" submit="false"
script="#{javascript: myBean.myObject.get('onClick')}">
</xp:eventHandler>
</xp:button>
This should give you the end result of seeing 'you clicked?' alert.
You can also inspect how this has all been generated in the script block near the end of the page using 'view Source' or your favourite web browser developer tools:
function view__id1__id2_clientSide_onclick(thisEvent) {
alert('you clicked?');
}
XSP.addOnLoad(function() {
XSP.attachEvent("view:_id1:_id2", "view:_id1:button1", "onclick",
view__id1__id2_clientSide_onclick, false, 2);
});
Let me know if anything isn't clear, hope it helps!
Does obj.onClick already give you a handle to the function returned by the Java class? If it does then you should be able to call it using the call or apply methods that are available in JavaScript:
obj.onClick.call();
obj.onClick.apply();
More details about those two methods can be found here: What is the difference between call and apply?

get the path of java file changed using IElementChangedListener

I am using IElementChangedListener to listen to changes in the Java Model in eclipse plug-in I am making.
Is there any way I can get the path of the java file that had the change using this Listener or should I try a different Listener?
Any suggestions or links are appreciated.
Thanks
The IJavaElementDelta available in the ElementChangedEvent event has a getElement() method which returns an IJavaElement.
IJavaElement has a getPath() method which 'Returns the path to the innermost resource enclosing this element'.
You may have to look at the added / affected / changed children in the delta to get all changes.
Try the following:
elementChangedListener.elementChanged(ElementChangedEvent event) {
IJavaElementDelta delta = ElementChangedEvent.getDelta();
int kind = delta.getKind();
int flags = delta.getFlags();
// flags -> F_ARCHIVE_CONTENT_CHANGED, F_ADDED_TO_CLASSPATH, F_CLASSPATH_REORDER, F_REMOVED_FROM_CLASSPATH
if ((delta.getFlags() & IJavaElementDelta.F_ARCHIVE_CONTENT_CHANGED) != 0) {
// The contents of an archive has changed in some way
}
}
See documentation of org.eclipse.jdt.core.IJavaElementDelta

Two Threads calling one Method

I have a method which writes a XML- File like this:
private void doProcess() {
Element rootElement = mDoc.createElement("Test");
mDoc.appendChild(rootElement);
....... I build the whole document here...
}
But this method can be called by multiple Threads, so for example if thwo threads call this method on the same time i get an
): org.w3c.dom.DOMException: Only one root element allowed
I already tried it with an reentrantlock, but this didn´t work...Can somebody give me a hint?
Edit:
I dont build the Document with multiple Threads...Every Call of my Method builds his own Doc...So sometimes in my Application it could happen that my Method will be called two times at the same time...And there´s my Problem...
In the question you state:
I dont build the Document with multiple Threads...Every Call of my Method builds his own Doc
Currently the code given shares a single doc between all calls to the function. In order to have each call to the function work on it's own document, you need to modify the code such that each call has it's own doc.
This can be done either by creating and returning a new document object
private XMLDocument doProcess() {
XMLDocument mDoc = new XMLDocument(); // or simmilar depending on XML library
Element rootElement = mDoc.createElement("Test");
mDoc.appendChild(rootElement);
// ....... I build the whole document here...
return mDoc; //return the document object
}
Or, by passing the document object in as a parameter
private void doProcess(XMLDocument mDoc) { ... }
An xml can has only ONE root, so this may be answer to your question. You can instantiate an root element outside this method and add element to this root inside method each time.

Redirect with anchor in play 2

I'm looking for possibility to add anchor to url returned in controller:
public static Result open(String id) {
// here I want to add acnhor like #foo to the produced url
return redirect(routes.MyPage.show(id));
}
I found that it was possible in play 1 using addRef method, but I couldn't find any replacement of the method in play 2.
Of course I can use concatenation like:
public static Result open(String id) {
// here I want to add acnhor like #foo to the produced url
return redirect(routes.MyPage.show(id).url + "#foo");
}
But it seems ugly.
Thank you for any help! Have a good day!
Before trying to answer that question.
I should recommend you change whatever behavior you're currently setting.
Because, an URL fragment's purpose is client side only. Such fragment is never sent to the server, so that it's cumbersome to do the opposite.
However, here is the embryo of a (quite?) elegant solution that you could follow.
What I'll try to do is to leave the browser deal with the fragment, in order to keep potential behaviors (f.i. go to ID or even deal with history...).
To do so, you could add an implicit parameter to your main template which will define the fragment that the URL should have:
#(title: String)(content: Html)(urlFragment:Option[UrlFragment] = None)
As you can see I wrapped the parameter in an Option and default'ed it to None (in order to avoid AMAP pollution).
Also, it simply wraps a String but you could use String alone -- using a dedicated type will enforce the semantic. Here is the definition:
case class UrlFragment(hash:String)
Very simple.
Now here is how to tell the browser to deal with it. Right before the end of the head element, and the start of body, just add the following:
#urlFragment.map { f =>
<script>
$(function() {
//after everything is ready, so that other mechanism will be able to use the change hash event...
document.location.hash = "#Html(#f.hash)";
});
</script>
}
As you can see, using map (that is when the urlFragment is not None) we add a script block that will set the hash available in urlFragment.
This might be a start, however... Think about another solution for the whole scenario.
As of Play 2.4, it's possible to use Call.withFragment().
routes.Application.index.withFragment("some-id").absoluteURL(request)
This was added by PR #4152.

How do I get the RDF resource that represents the objects which have a certain [property,object] pair?

Okay, to clarify, I have an XML/RDF file that describes data with a natural categorical tree structure (like folders and files). The data is not structured in a tree, rather, there is information that explains how to rebuild the tree (namely the nested set values of each node). I am starting with no knowledge other than the assumption that some statement in the file has a RootTree property who's object is the URI of the statement describing the root node of the tree.
Obtaining that object is easy, I simply use:
// Obtain the node describing the root of the Pearltree.
mRootProp = mModel.createProperty(Pearltree.RDF.PearlTreeNS, "rootTree");
NodeIterator roots = mModel.listObjectsOfProperty(mRootProp);
Now, I am further able to list all statements which have the property pt:parentTree and the object roots.nextNode():
StmtIterator sit = mModel.listStatements(null, RDF.ParentTree, rootNode);
This gives me a list of all such statements. These statements are part of elements that look like such in the RDF/XML file (note these have a different parentTree value but appear in the same context):
<pt:RootPearl rdf:about="http://www.pearltrees.com/dcow/pearltrees-videos/id5296268#rootPearl">
<dcterms:title><![CDATA[Pearltrees videos]]></dcterms:title>
<pt:parentTree rdf:resource="http://www.pearltrees.com/dcow/pearltrees-videos/id5296268" />
<pt:inTreeSinceDate>2012-06-11T20:25:55</pt:inTreeSinceDate>
<pt:leftPos>1</pt:leftPos>
<pt:rightPos>8</pt:rightPos>
</pt:RootPearl>
<pt:PagePearl rdf:about="http://www.pearltrees.com/dcow/pearltrees-videos/id5296268#pearl46838293">
<dcterms:title><![CDATA[why Pearltrees?]]></dcterms:title>
<dcterms:identifier>http://www.youtube.com/watch?v%3di4rDqMMFx8g</dcterms:identifier>
<pt:parentTree rdf:resource="http://www.pearltrees.com/dcow/pearltrees-videos/id5296268" />
<pt:inTreeSinceDate>2012-06-11T20:25:55</pt:inTreeSinceDate>
<pt:leftPos>2</pt:leftPos>
<pt:rightPos>3</pt:rightPos>
</pt:PagePearl>
...
Now, what I would like to do is obtain a reference to all statements with subject sit.nextStatement()'s subject. In this example:
"http://www.pearltrees.com/dcow/pearltrees-videos/id5296268#rootPearl"
and
"http://www.pearltrees.com/dcow/pearltrees-videos/id5296268#pearl46838293"
My goal is to obtain the content of each element including its rightPos and leftPos so I can reconstruct the tree.
You can simplify your code somewhat as follows:
mRootProp = mModel.createProperty(Pearltree.RDF.PearlTreeNS, "rootTree");
Resource root = mModel.listResourcesWithProperty( mRootProp ).next();
This assumes you know you have exactly one root per model. If that might not be true, modify the code accordingly.
The method:
getSubject()
of a Statement will return the Subject as a Resource. You can then use the
getProperty(Property p)
method of the returned Resource to obtain the Statements that include the property in question.
So, in my case, I use:
Resource r;
Statement title, id, lpos, rpos;
while(sit.hasNext()) {
r = sit.nextStatement().getSubject();
title = r.getProperty(DCTerms.title);
id = r.getProperty(DCTerms.identifier);
lpos = r.getProperty(PearlTree.RDF.leftPos);
rpos = r.getProperty(PearlTree.RDF.rightPos);
...
}

Categories