1. /*
  2. * Copyright 1999-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. * $Id: FuncId.java,v 1.14 2004/02/17 04:34:01 minchau Exp $
  18. */
  19. package com.sun.org.apache.xpath.internal.functions;
  20. import java.util.StringTokenizer;
  21. import com.sun.org.apache.xml.internal.dtm.DTM;
  22. import com.sun.org.apache.xml.internal.dtm.DTMIterator;
  23. import com.sun.org.apache.xml.internal.utils.StringVector;
  24. import com.sun.org.apache.xpath.internal.NodeSetDTM;
  25. import com.sun.org.apache.xpath.internal.XPathContext;
  26. import com.sun.org.apache.xpath.internal.objects.XNodeSet;
  27. import com.sun.org.apache.xpath.internal.objects.XObject;
  28. import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
  29. /**
  30. * Execute the Id() function.
  31. * @xsl.usage advanced
  32. */
  33. public class FuncId extends FunctionOneArg
  34. {
  35. /**
  36. * Fill in a list with nodes that match a space delimited list if ID
  37. * ID references.
  38. *
  39. * @param xctxt The runtime XPath context.
  40. * @param docContext The document where the nodes are being looked for.
  41. * @param refval A space delimited list of ID references.
  42. * @param usedrefs List of references for which nodes were found.
  43. * @param nodeSet Node set where the nodes will be added to.
  44. * @param mayBeMore true if there is another set of nodes to be looked for.
  45. *
  46. * @return The usedrefs value.
  47. */
  48. private StringVector getNodesByID(XPathContext xctxt, int docContext,
  49. String refval, StringVector usedrefs,
  50. NodeSetDTM nodeSet, boolean mayBeMore)
  51. {
  52. if (null != refval)
  53. {
  54. String ref = null;
  55. // DOMHelper dh = xctxt.getDOMHelper();
  56. StringTokenizer tokenizer = new StringTokenizer(refval);
  57. boolean hasMore = tokenizer.hasMoreTokens();
  58. DTM dtm = xctxt.getDTM(docContext);
  59. while (hasMore)
  60. {
  61. ref = tokenizer.nextToken();
  62. hasMore = tokenizer.hasMoreTokens();
  63. if ((null != usedrefs) && usedrefs.contains(ref))
  64. {
  65. ref = null;
  66. continue;
  67. }
  68. int node = dtm.getElementById(ref);
  69. if (DTM.NULL != node)
  70. nodeSet.addNodeInDocOrder(node, xctxt);
  71. if ((null != ref) && (hasMore || mayBeMore))
  72. {
  73. if (null == usedrefs)
  74. usedrefs = new StringVector();
  75. usedrefs.addElement(ref);
  76. }
  77. }
  78. }
  79. return usedrefs;
  80. }
  81. /**
  82. * Execute the function. The function must return
  83. * a valid object.
  84. * @param xctxt The current execution context.
  85. * @return A valid XObject.
  86. *
  87. * @throws javax.xml.transform.TransformerException
  88. */
  89. public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
  90. {
  91. int context = xctxt.getCurrentNode();
  92. DTM dtm = xctxt.getDTM(context);
  93. int docContext = dtm.getDocument();
  94. if (DTM.NULL == docContext)
  95. error(xctxt, XPATHErrorResources.ER_CONTEXT_HAS_NO_OWNERDOC, null);
  96. XObject arg = m_arg0.execute(xctxt);
  97. int argType = arg.getType();
  98. XNodeSet nodes = new XNodeSet(xctxt.getDTMManager());
  99. NodeSetDTM nodeSet = nodes.mutableNodeset();
  100. if (XObject.CLASS_NODESET == argType)
  101. {
  102. DTMIterator ni = arg.iter();
  103. StringVector usedrefs = null;
  104. int pos = ni.nextNode();
  105. while (DTM.NULL != pos)
  106. {
  107. DTM ndtm = ni.getDTM(pos);
  108. String refval = ndtm.getStringValue(pos).toString();
  109. pos = ni.nextNode();
  110. usedrefs = getNodesByID(xctxt, docContext, refval, usedrefs, nodeSet,
  111. DTM.NULL != pos);
  112. }
  113. // ni.detach();
  114. }
  115. else if (XObject.CLASS_NULL == argType)
  116. {
  117. return nodes;
  118. }
  119. else
  120. {
  121. String refval = arg.str();
  122. getNodesByID(xctxt, docContext, refval, null, nodeSet, false);
  123. }
  124. return nodes;
  125. }
  126. }