001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: FuncId.java 468655 2006-10-28 07:12:06Z minchau $ 020 */ 021 package org.apache.xpath.functions; 022 023 import java.util.StringTokenizer; 024 025 import org.apache.xml.dtm.DTM; 026 import org.apache.xml.dtm.DTMIterator; 027 import org.apache.xml.utils.StringVector; 028 import org.apache.xpath.NodeSetDTM; 029 import org.apache.xpath.XPathContext; 030 import org.apache.xpath.objects.XNodeSet; 031 import org.apache.xpath.objects.XObject; 032 import org.apache.xpath.res.XPATHErrorResources; 033 034 /** 035 * Execute the Id() function. 036 * @xsl.usage advanced 037 */ 038 public class FuncId extends FunctionOneArg 039 { 040 static final long serialVersionUID = 8930573966143567310L; 041 042 /** 043 * Fill in a list with nodes that match a space delimited list if ID 044 * ID references. 045 * 046 * @param xctxt The runtime XPath context. 047 * @param docContext The document where the nodes are being looked for. 048 * @param refval A space delimited list of ID references. 049 * @param usedrefs List of references for which nodes were found. 050 * @param nodeSet Node set where the nodes will be added to. 051 * @param mayBeMore true if there is another set of nodes to be looked for. 052 * 053 * @return The usedrefs value. 054 */ 055 private StringVector getNodesByID(XPathContext xctxt, int docContext, 056 String refval, StringVector usedrefs, 057 NodeSetDTM nodeSet, boolean mayBeMore) 058 { 059 060 if (null != refval) 061 { 062 String ref = null; 063 // DOMHelper dh = xctxt.getDOMHelper(); 064 StringTokenizer tokenizer = new StringTokenizer(refval); 065 boolean hasMore = tokenizer.hasMoreTokens(); 066 DTM dtm = xctxt.getDTM(docContext); 067 068 while (hasMore) 069 { 070 ref = tokenizer.nextToken(); 071 hasMore = tokenizer.hasMoreTokens(); 072 073 if ((null != usedrefs) && usedrefs.contains(ref)) 074 { 075 ref = null; 076 077 continue; 078 } 079 080 int node = dtm.getElementById(ref); 081 082 if (DTM.NULL != node) 083 nodeSet.addNodeInDocOrder(node, xctxt); 084 085 if ((null != ref) && (hasMore || mayBeMore)) 086 { 087 if (null == usedrefs) 088 usedrefs = new StringVector(); 089 090 usedrefs.addElement(ref); 091 } 092 } 093 } 094 095 return usedrefs; 096 } 097 098 /** 099 * Execute the function. The function must return 100 * a valid object. 101 * @param xctxt The current execution context. 102 * @return A valid XObject. 103 * 104 * @throws javax.xml.transform.TransformerException 105 */ 106 public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException 107 { 108 109 int context = xctxt.getCurrentNode(); 110 DTM dtm = xctxt.getDTM(context); 111 int docContext = dtm.getDocument(); 112 113 if (DTM.NULL == docContext) 114 error(xctxt, XPATHErrorResources.ER_CONTEXT_HAS_NO_OWNERDOC, null); 115 116 XObject arg = m_arg0.execute(xctxt); 117 int argType = arg.getType(); 118 XNodeSet nodes = new XNodeSet(xctxt.getDTMManager()); 119 NodeSetDTM nodeSet = nodes.mutableNodeset(); 120 121 if (XObject.CLASS_NODESET == argType) 122 { 123 DTMIterator ni = arg.iter(); 124 StringVector usedrefs = null; 125 int pos = ni.nextNode(); 126 127 while (DTM.NULL != pos) 128 { 129 DTM ndtm = ni.getDTM(pos); 130 String refval = ndtm.getStringValue(pos).toString(); 131 132 pos = ni.nextNode(); 133 usedrefs = getNodesByID(xctxt, docContext, refval, usedrefs, nodeSet, 134 DTM.NULL != pos); 135 } 136 // ni.detach(); 137 } 138 else if (XObject.CLASS_NULL == argType) 139 { 140 return nodes; 141 } 142 else 143 { 144 String refval = arg.str(); 145 146 getNodesByID(xctxt, docContext, refval, null, nodeSet, false); 147 } 148 149 return nodes; 150 } 151 }