Details
-
Bug
-
Status: Open
-
Major
-
Resolution: Unresolved
-
2.3.25-incubating
-
None
-
None
Description
XPath expressions that contains text() doesn't evaluate to the correct value when the model isn't normalized and includes multiple text nodes. This will happen when the xml-parser creates multiple text nodes due to performance or memory reasons and is a fully normal behaviour.
The solution in the function executeQuery with the NodeIterator (files: freemarker/ext/dom/SunInternalXalanXPathSupport.java and freemarker/ext/dom/XalanXPathSupport.java) doesn't handle adjacent(siblings) textnodes. The problem probably also exists for CDATA nodes. I don't know if the jaxen solution behaves in the same manner.
...XPathSupport.java
synchronized public TemplateModel executeQuery(Object context, String xpathQuery) throws TemplateModelException { ... NodeIterator nodeIterator = xresult.nodeset(); Node n; do { n = nodeIterator.nextNode(); if (n != null) { result.add(n); } } while (n != null); ...
Sample code to reproduce
Reproduce.java
Configuration cfg = new Configuration(Configuration.VERSION_2_3_25); cfg.setDefaultEncoding("UTF-8"); ClassTemplateLoader ctl = new ClassTemplateLoader(App.class, "/"); cfg.setTemplateLoader(ctl); // --- sample.ftl --- // <#ftl> // Text:${model["//root/text()"]} // Node:${model["//root"]} Template temp = cfg.getTemplate("sample.ftl"); // --- Model --- // Element:root // |- TextNode:SA // |- TextNode:MPLE DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); Document doc = docBuilder.newDocument(); Element rootElement = doc.createElement("root"); doc.appendChild(rootElement); Text text = doc.createTextNode("SA"); rootElement.appendChild(text); text = doc.createTextNode("MPLE"); rootElement.appendChild(text); Map<String, Object> model = new HashMap<String, Object>(); model.put("model", doc); StringWriter sw = new StringWriter(); temp.process(model, sw); System.out.println(sw.toString()); // --- Actual output --- // Text:SA // Node:SAMPLE // --- Expected output --- // Text:SAMPLE // Node:SAMPLE