2017-10-13 0:33 GMT+02:00 Daniel Dekany <ddek...@apache.org>:

> Actually, in `someNode.something` (which is the same as
> `someNode["something"]`) the "something" meant to be XPath (appart
> from a few FreeMarker-specific things).

But as you have seen in some
> very simple cases we solve the XPath query "natively" instead of
> delegating it to XPath.


Thanks Daniel, good to know. So there probably was a reason for this too in
the past.

Now if profiling reliably(!) shows that it's
> indeed XPath in this case that's so slow, then it seems it would be

better if we take over even more cases from XPath, such as
> "@something"... I will have to look into that though. (This can be
> tricky though, as you replace the implementation of that kind of query
> under thousands of already working applications, so it really has to
> behave exactly like the real thing earlier.


I agree, this is very risky and my poor-mans "benchmark" is not reliable at
all. I can try if I can find some time to come up with a programmatic
test-case maybe which makes it better visible.
Your insights tell me so far that we better go with the custom
TemplateMethodModel for now (shortterm) to solve our specific business
problem. Less risk.

I will try fiddling around with the sources of
freemarker.ext.dom.NodeModel.get(String)
etc. which already do some "key.startsWith("@@")" checks. Maybe I find the
place where to add an improvement and try it out.


> That's unlike with
> product.PRODUCT_DETAILS which was never delegated to the real XPath
> implementation.)
>

> Thursday, October 12, 2017, 7:35:42 PM, Christoph Rüger wrote:
>
> > Hi,
> >
> > we have the following XML snippet:
> >
> > <PRODUCT_DETAILS>
> >   <INTERNATIONAL_PID *type="GTIN"*>4011395534809</INTERNATIONAL_PID>
> > </PRODUCT_DETAILS>
> >
> > We iterate over XML-Nodes like this:
> >
> > <#list product["PRODUCT_DETAILS"]?children as detail>
>
> Note that you can write `product["PRODUCT_DETAILS"]` as
> `product.PRODUCT_DETAILS`.
>

Ok. Usually we do. Not sure why we didn't here. Was a code snippet from a
colleague :)


>
> >   nodeValue: ${detail!}
> > </#list>
> >
> > This code snippet is pretty fast (result appears after e.g. 3 seconds).
> But
> > when we turn it into this and try to add the node attribute "type"...
> >
> > <#list product["PRODUCT_DETAILS"]?children as detail>
> >  <#if detail.*@type*[0]?? && detail.*@type*[0] == "GTIN">
> >   node*Attribute* type: ${detail.@type}
> >   nodeValue: ${detail!}
> >  </#if>
> > </#list>
> >
> > ...it gets very very slow (result appears after > 1 minute). We have a
> large XML with >> 1000 products here.
> >
> > I have digged a little bit in the code and found that when the check for
> > *detail.@type[0]??* is in the mix, then
> > *freemarker.ext.dom.NodeModel.get(String) *is jumping into the
> else-branch
> > which uses XPath:
> >
> >  public TemplateModel get(String key) throws TemplateModelException {
> >
> >    if (key.startsWith("@@")) {
> >     // ....
> >
> > }
> >
> > else{
> >
> > XPathSupport xps = getXPathSupport();
> >           if (xps != null) {
> >
> > *return xps.executeQuery(node, key);*            }
> >
> > }
> >
> > This *xps.executeQuery(node, key); *seems to be the reason why it gets
> > slow. Internally it
> > calls
> > freemarker.ext.dom.SunInternalXalanXPathSupport.executeQuery(Object,
> > String)
> >
> > To work around this problem I have tried creating an own
> > TemplateMethodModel ${nodeAttrib(node, attributename)}
> >
> > where I do something like this (I know it's ugly but experimental...) :
> >
> > new TemplateMethodModelEx(){
> >
> > public Object exec(List arg0) throws TemplateModelException {
> >
> > Object node = arg0.get(0);
> >
> > Object attribute = arg0.get(1);
> >
> > if(node instanceof NodeModel) {
> >
> > NamedNodeMap attributes = ((NodeModel) node).getNode().getAttributes();
> >
> > if(attributes != null && attributes.getLength() > 0) {
> >
> > Node namedItem = *attributes.getNamedItem(attribute.toString())*;
> >
> > if(namedItem != null) {
> >
> > System.out.println(namedItem.getNodeValue());
> >
> > return namedItem.getNodeValue();
> >
> > }
> >
> > else {
> >
> > return "";
> >
> > }
> >
> > }
> >
> > }
> >
> > return "";
> >
> > }
> >
> >
> > When we then use this it is much faster:
> > <#list product["PRODUCT_DETAILS"]?children as detail>
> >   <#if *nodeAttribute(details, "type")!* == "GTIN" >
> >    node*Attribute* type: ${*nodeAttribute(details, "type")!*}
> >    nodeValue: ${detail!}
> >   </#if>
> > </#list>
> >
> > It seems that NamedNodeMap.*getNamedItem() *much faster and does not use
> > XPath. Although it is also iterating internally over the whole array to
> > find the index of the attribute - the overhead seems to be less then
> XPath.
> >
> > My questions are:
> > 1. What is the reason that *detail.@type[0]?? *causes a heavy XPath
> > evaluation under the hood?
> > 2. Are we doing something wrong?
> > 3. Should we go the custom TemplateMethodModel way? Is this approach ok?
> >
> > I hope this was understandable.
> >
> > Thanks
> > Christoph
> >
>
> --
> Thanks,
>  Daniel Dekany
>
>


-- 
Christoph Rüger, Geschäftsführer
Synesty <https://synesty.com/> - Anbinden und Automatisieren ohne
Programmieren - Automatisierung, Schnittstellen, Datenfeeds

Xing: https://www.xing.com/profile/Christoph_Rueger2
LinkedIn: http://www.linkedin.com/pub/christoph-rueger/a/685/198

-- 
Synesty GmbH
Moritz-von-Rohr-Str. 1a
07745 Jena
Tel.: +49 3641 559649
Fax.: +49 3641 5596499
Internet: http://synesty.com

Geschäftsführer: Christoph Rüger
Unternehmenssitz: Jena
Handelsregister B beim Amtsgericht: Jena
Handelsregister-Nummer: HRB 508766
Ust-IdNr.: DE287564982

Reply via email to