Project

Profile

Help

Bug #5727

closed

Xqueries with Domino do not work with a document having non namespace aware attributes

Added by Jai Mashalkar over 1 year ago. Updated 5 months ago.

Status:
Closed
Priority:
Normal
Assignee:
Category:
DOM Interface
Sprint/Milestone:
-
Start date:
2022-11-04
Due date:
% Done:

100%

Estimated time:
Legacy ID:
Applies to branch:
10, 11, trunk
Fix Committed on Branch:
10, 11, trunk
Fixed in Maintenance Release:
Platforms:
Java

Description

Xquery outputing a complex element does not work with domino, if xml has any attribute that is not namespace aware or its created with a document builder that’s not namespace aware. This seems to be because Node.getlocalName() does not have an implementation for Domino nodes, similar to whats present for TinyTree and DOMWrapper.

DomWrapper:
public static String getLocalName(Node node) {
/* 349 */       String s = node.getLocalName();
/* 350 */       if (s == null) {
/*     */ 
/* 352 */          String n = node.getNodeName();
/* 353 */          int colon = n.indexOf(58);
/* 354 */          return colon >= 0 ? n.substring(colon + 1) : n;
/*     */ 
/*     */ 
/*     */ 
/*     */       } else {
/* 359 */          return s;
/*     */       }
/*     */    }



TinyTree:
 public String getLocalPart() {
/* 176 */       return this.tree.getNamePool().getLocalName(this.tree.attCode[this.nodeNr]);
/*     */    }


Domino:
/*     */    public String getLocalPart() {
/* 214 */       return this.domAttr.getLocalName();
/*     */    }

/**
     * Introduced in DOM Level 2. <p>
     *
     * Returns the local part of the qualified name of this node.
     * For nodes created with a DOM Level 1 method, such as createElement
     * from the Document interface, and for nodes of any type other than
     * ELEMENT_NODE and ATTRIBUTE_NODE this is the same as the nodeName
     * attribute.
     * @since WD-DOM-Level-2-19990923
     * @see AttrNSImpl
     * @see ElementNSImpl
     */
    public String             getLocalName()
    {
        return null;
    }

Example:
public class XqueryTestBug {
	static String htdQuery = "<a>{(.)/htd:task}</a>";
	static boolean useDomino = true;
	public static void main(String argv[]) throws Exception {
		try {
			run(argv[0]);
		} catch (SaxonApiException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	private static void run(String xmlFile) throws SaxonApiException, IOException, Exception {
		// the Saxon processor object
		String 	queryString = htdQuery;
		EnterpriseConfiguration pc = setupSaxonAndGetConfig();
		pc.registerExternalObjectModel(DOMEnvelope.getInstance());
		pc.registerExternalObjectModel(DOMObjectModel.getInstance());

		Processor saxon = new Processor(pc);
		XQueryCompiler compiler = saxon.newXQueryCompiler();
		compiler.declareNamespace("htd", "http://www.example.org/WS-HT");
		compiler.declareNamespace("trt", "http://schemas.active-endpoints.com/b4p/wshumantask/2007/10/aeb4p-task-rt.xsd");
		compiler.declareNamespace("tlc", "http://schemas.active-endpoints.com/b4p/wshumantask/2007/10/aeb4p-task-lifecycle-wsdl.xsd");
		compiler.declareNamespace("sf", "http://schemas.active-endpoints.com/appmodules/screenflow/2010/10/avosScreenflow.xsd");

		XQueryExecutable exec = compiler.compile(queryString);
		XQueryEvaluator query = exec.load();

		//load document
		String input = FileUtils.readFileToString(new File(xmlFile));
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		javax.xml.parsers.DocumentBuilder documentBuilder = factory.newDocumentBuilder();
		InputSource inputSource = new InputSource(new StringReader(input));
		org.w3c.dom.Document doc = documentBuilder.parse(inputSource);

		if(useDomino) {
			DominoTree domTree = DominoTree.makeTree(doc.getDocumentElement().getOwnerDocument(), pc, "systemID");
			SequenceIterator next = domTree.getRootNode().iterateAxis(AxisInfo.CHILD,NodeKindTest.ELEMENT);
			GroundedValue gv = SequenceTool.toGroundedValue(next);
			DominoNode elNode = (DominoNode) gv.itemAt(0);

			query.setContextItem(    (XdmNode) XdmValue.wrap(gv));
		} else {
			TransformerFactory tfactory = new EnterpriseTransformerFactory(pc);
			final Transformer transformer = tfactory.newTransformer();
			PipelineConfiguration pipeconfig = pc.makePipelineConfiguration();
			// set up holder for the output
			final TinyBuilder outputTarget = new TinyBuilder(
					pipeconfig);

			transformer.transform(new DOMSource(doc), outputTarget);

			TinyTree tt = outputTarget.getTree();
			NodeInfo nodeInfo =  tt.getRootNode();
			query.setContextItem(new XdmNode(nodeInfo));
		}

		XdmValue result = query.evaluate();
	}
}

Exception seen with Domino:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.equals(Object)" because the return value of "net.sf.saxon.om.NodeName.getLocalPart()" is null
	at net.sf.saxon.om.NameOfNode.equals(NameOfNode.java:177)
	at net.sf.saxon.om.SingletonAttributeMap.put(SingletonAttributeMap.java:69)
	at net.sf.saxon.om.NodeInfo.attributes(NodeInfo.java:482)
	at net.sf.saxon.tree.util.Navigator.copy(Navigator.java:678)
	at net.sf.saxon.om.NodeInfo.copy(NodeInfo.java:522)
	at net.sf.saxon.event.ComplexContentOutputter.decompose(ComplexContentOutputter.java:893)
	at net.sf.saxon.event.ComplexContentOutputter.append(ComplexContentOutputter.java:658)
	at net.sf.saxon.expr.Expression.lambda$process$0(Expression.java:948)
	at net.sf.saxon.om.SequenceTool.supply(SequenceTool.java:147)
	at net.sf.saxon.expr.Expression.process(Expression.java:948)
	at net.sf.saxon.expr.instruct.ElementCreator.processLeavingTail(ElementCreator.java:357)
	at net.sf.saxon.expr.instruct.ElementCreator.processLeavingTail(ElementCreator.java:298)
	at net.sf.saxon.expr.instruct.Instruction.process(Instruction.java:142)
	at net.sf.saxon.expr.parser.ExpressionTool.getIteratorFromProcessMethod(ExpressionTool.java:678)
	at net.sf.saxon.expr.instruct.Instruction.iterate(Instruction.java:374)
	at com.saxonica.ee.bytecode.ByteCodeCandidate.iterate(ByteCodeCandidate.java:328)
	at net.sf.saxon.query.XQueryExpression.iterator(XQueryExpression.java:378)
	at net.sf.saxon.s9api.XQueryEvaluator.evaluate(XQueryEvaluator.java:520)
	at XqueryTest.runStatic(XqueryTest.java:474)
	at XqueryTest.run(XqueryTest.java:140)
	at XqueryTest.main(XqueryTest.java:116)

Actions #1

Updated by Michael Kay over 1 year ago

Saxon has never claimed to support a non-namespace-aware DOM.

One of the issues is that DOM provides no interrogative method that allows us to discover whether it's namespace-aware or not, and it's very expensive and inefficient to try and cater for both in the same code.

If there are small fixes that stop things falling over or improve diagnostics, then we can make them. But the general rule is, we only support DOM trees built using namespace-aware interfaces.

Actions #2

Updated by Jai Mashalkar over 1 year ago

The request here, is to add an implementation for handling localPart being null, similar to what is being done for DOM and TinyTree. Would that be feasible to do? Also, could you tell what are the other differences between things supported for Domino and TinyTree/DOM? As we are looking to push this to enterprise software in production.

Actions #3

Updated by Michael Kay over 1 year ago

I would strongly suggest you don't go into production with a non-namespace-aware DOM, whether using Domino or otherwise, as it's not something we test.

With a namespace-aware DOM, in principle using Domino shouldn't affect the outcome. But there are all sorts of edge conditions where it might. For example, the effect of mutations to the DOM while a query or transformation is in progress might be quite different -- similarly thread safety. These are all basically areas where it's best to tread very carefully.

Do be aware that even with Domino, navigating a DOM using Saxon is far slower than a native TinyTree.

Actions #4

Updated by Jai Mashalkar over 1 year ago

Actually our DOM is built using a namespace aware DOM builder. However, we use the method element.setAttribute() instead of element.setAttributNS(). This should be supported?

Actions #5

Updated by Michael Kay over 1 year ago

This is exactly the kind of thing that makes navigating a user-supplied DOM an absolute nightmare. There are so many ways of getting the DOM into strange states, it's impossible to test them all. Using APIs like this, you can create all kind of inconsistencies (attributes with prefixes that aren't declared, duplicate attributes, etc etc.). We can fix each problem when we find it, but it's never going to be robust.

Actions #6

Updated by Jai Mashalkar over 1 year ago

ok, thanks for the inputs. We are trying to make Domino work as it would end up using lesser memory than tinytree, for big documents in our execution context. Before closing off, could you confirm if functionally, DominoTree is expected to behave the same as TinyTree? If there are any differences could you point us to them?

Actions #7

Updated by Michael Kay over 1 year ago

  • Description updated (diff)
Actions #8

Updated by Michael Kay over 1 year ago

Could you provide a source document that demonstrates the problem please?

I'm currently running your code without any failure.

Actions #9

Updated by Michael Kay over 1 year ago

Problem now reproduced (well, a slightly different point of failure, but close enough).

Actions #10

Updated by Michael Kay over 1 year ago

I can change DominoAttr.getLocalPart() easily enough to stop it crashing when the it's a level-1 node, however, the effect is that this query produces an output that's incorrect, because it creates a no-namespace attribute in the result ignoring any namespace in the source. In fact it creates an attribute node in the result tree that has a prefix but no namespace, which serializes correctly, but could cause problems in subsequent processing, because XDM consistency requires that if an attribute has a prefix, then it has a namespace).

Incorrect output in this case is probably better than a crash; and it's probably fine if the document actually doesn't use namespaces (though it seems this one does). I'll apply the patch, but it's only sticky-plaster, the basic processing is still unsound.

Actions #11

Updated by Michael Kay over 1 year ago

  • Category set to DOM Interface
  • Status changed from New to Resolved
  • Assignee set to Michael Kay
  • Applies to branch 11, trunk added
  • Fix Committed on Branch 11, trunk added
  • Platforms Java added
Actions #12

Updated by Jai Mashalkar over 1 year ago

hi, sorry for the delay just seeing your messages. I made a mistake by not specifying the release version. We are currently using 10.8 version of saxon-ee. Is it possible to get a patch applied on that?

Actions #13

Updated by Michael Kay over 1 year ago

  • Fix Committed on Branch 10 added

I've committed the patch on the 10.x branch as well. We've got a 10.x maintenance release on our TODO list, but it's taking a while for it to reach the top of the list...

Actions #14

Updated by Community Admin over 1 year ago

  • % Done changed from 0 to 100
  • Fixed in Maintenance Release 12.0 added

Bug issue fix applied in the Saxon 12.0 Major Release. Leaving this bug marked as Resolved until fix applied

Actions #15

Updated by O'Neil Delpratt about 1 year ago

  • Fixed in Maintenance Release 11.5 added

Bug fix applied in the Saxon 11.5 maintenance release.

Actions #16

Updated by O'Neil Delpratt 12 months ago

  • Status changed from Resolved to Closed
Actions #17

Updated by Debbie Lockett 5 months ago

  • Applies to branch 10 added
  • Fixed in Maintenance Release 10.9 added

The bug fix was also applied in the Saxon 10.9 maintenance release (2023-02-16).

Please register to edit this issue

Also available in: Atom PDF