1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xalan" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 1999, Lotus
  53. * Development Corporation., http://www.lotus.com. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package org.apache.xalan.templates;
  58. import org.apache.xml.dtm.DTM;
  59. import java.util.Vector;
  60. import java.util.StringTokenizer;
  61. import org.apache.xml.utils.StringBufferPool;
  62. import org.apache.xml.utils.FastStringBuffer;
  63. import javax.xml.transform.TransformerException;
  64. import org.apache.xpath.XPathContext;
  65. import org.apache.xpath.XPath;
  66. import org.apache.xalan.res.XSLTErrorResources;
  67. import org.apache.xml.utils.PrefixResolver;
  68. import org.apache.xalan.res.XSLMessages;
  69. import org.apache.xalan.processor.StylesheetHandler;
  70. import javax.xml.transform.ErrorListener;
  71. /**
  72. * <meta name="usage" content="advanced"/>
  73. * Class to hold an Attribute Value Template.
  74. */
  75. public class AVT implements java.io.Serializable, XSLTVisitable
  76. {
  77. /**
  78. * If the AVT is not complex, just hold the simple string.
  79. * @serial
  80. */
  81. private String m_simpleString = null;
  82. /**
  83. * If the AVT is complex, hold a Vector of AVTParts.
  84. * @serial
  85. */
  86. private Vector m_parts = null;
  87. /**
  88. * The name of the attribute.
  89. * @serial
  90. */
  91. private String m_rawName;
  92. /**
  93. * Get the raw name of the attribute, with the prefix unprocessed.
  94. *
  95. * @return non-null reference to prefixed name.
  96. */
  97. public String getRawName()
  98. {
  99. return m_rawName;
  100. }
  101. /**
  102. * Get the raw name of the attribute, with the prefix unprocessed.
  103. *
  104. * @param rawName non-null reference to prefixed name.
  105. */
  106. public void setRawName(String rawName)
  107. {
  108. m_rawName = rawName;
  109. }
  110. /**
  111. * The name of the attribute.
  112. * @serial
  113. */
  114. private String m_name;
  115. /**
  116. * Get the local name of the attribute.
  117. *
  118. * @return non-null reference to name string.
  119. */
  120. public String getName()
  121. {
  122. return m_name;
  123. }
  124. /**
  125. * Set the local name of the attribute.
  126. *
  127. * @param name non-null reference to name string.
  128. */
  129. public void setName(String name)
  130. {
  131. m_name = name;
  132. }
  133. /**
  134. * The namespace URI of the owning attribute.
  135. * @serial
  136. */
  137. private String m_uri;
  138. /**
  139. * Get the namespace URI of the attribute.
  140. *
  141. * @return non-null reference to URI, "" if null namespace.
  142. */
  143. public String getURI()
  144. {
  145. return m_uri;
  146. }
  147. /**
  148. * Get the namespace URI of the attribute.
  149. *
  150. * @param uri non-null reference to URI, "" if null namespace.
  151. */
  152. public void setURI(String uri)
  153. {
  154. m_uri = uri;
  155. }
  156. /**
  157. * Construct an AVT by parsing the string, and either
  158. * constructing a vector of AVTParts, or simply hold
  159. * on to the string if the AVT is simple.
  160. *
  161. * @param handler non-null reference to StylesheetHandler that is constructing.
  162. * @param uri non-null reference to URI, "" if null namespace.
  163. * @param name non-null reference to name string.
  164. * @param rawName prefixed name.
  165. * @param stringedValue non-null raw string value.
  166. *
  167. * @throws javax.xml.transform.TransformerException
  168. */
  169. public AVT(StylesheetHandler handler, String uri, String name,
  170. String rawName, String stringedValue,
  171. ElemTemplateElement owner)
  172. throws javax.xml.transform.TransformerException
  173. {
  174. m_uri = uri;
  175. m_name = name;
  176. m_rawName = rawName;
  177. StringTokenizer tokenizer = new StringTokenizer(stringedValue, "{}\"\'",
  178. true);
  179. int nTokens = tokenizer.countTokens();
  180. if (nTokens < 2)
  181. {
  182. m_simpleString = stringedValue; // then do the simple thing
  183. }
  184. else
  185. {
  186. FastStringBuffer buffer = StringBufferPool.get();
  187. FastStringBuffer exprBuffer = StringBufferPool.get();
  188. try
  189. {
  190. m_parts = new Vector(nTokens + 1);
  191. String t = null; // base token
  192. String lookahead = null; // next token
  193. String error = null; // if non-null, break from loop
  194. while (tokenizer.hasMoreTokens())
  195. {
  196. if (lookahead != null)
  197. {
  198. t = lookahead;
  199. lookahead = null;
  200. }
  201. else
  202. t = tokenizer.nextToken();
  203. if (t.length() == 1)
  204. {
  205. switch (t.charAt(0))
  206. {
  207. case ('\"') :
  208. case ('\'') :
  209. {
  210. // just keep on going, since we're not in an attribute template
  211. buffer.append(t);
  212. break;
  213. }
  214. case ('{') :
  215. {
  216. try
  217. {
  218. // Attribute Value Template start
  219. lookahead = tokenizer.nextToken();
  220. if (lookahead.equals("{"))
  221. {
  222. // Double curlys mean escape to show curly
  223. buffer.append(lookahead);
  224. lookahead = null;
  225. break; // from switch
  226. }
  227. /*
  228. else if(lookahead.equals("\"") || lookahead.equals("\'"))
  229. {
  230. // Error. Expressions can not begin with quotes.
  231. error = "Expressions can not begin with quotes.";
  232. break; // from switch
  233. }
  234. */
  235. else
  236. {
  237. if (buffer.length() > 0)
  238. {
  239. m_parts.addElement(new AVTPartSimple(buffer.toString()));
  240. buffer.setLength(0);
  241. }
  242. exprBuffer.setLength(0);
  243. while (null != lookahead)
  244. {
  245. if (lookahead.length() == 1)
  246. {
  247. switch (lookahead.charAt(0))
  248. {
  249. case '\'' :
  250. case '\"' :
  251. {
  252. // String start
  253. exprBuffer.append(lookahead);
  254. String quote = lookahead;
  255. // Consume stuff 'till next quote
  256. lookahead = tokenizer.nextToken();
  257. while (!lookahead.equals(quote))
  258. {
  259. exprBuffer.append(lookahead);
  260. lookahead = tokenizer.nextToken();
  261. }
  262. exprBuffer.append(lookahead);
  263. lookahead = tokenizer.nextToken();
  264. break;
  265. }
  266. case '{' :
  267. {
  268. // What's another curly doing here?
  269. error = XSLMessages.createMessage(
  270. XSLTErrorResources.ER_NO_CURLYBRACE, null); //"Error: Can not have \"{\" within expression.";
  271. lookahead = null; // breaks out of inner while loop
  272. break;
  273. }
  274. case '}' :
  275. {
  276. // Proper close of attribute template.
  277. // Evaluate the expression.
  278. buffer.setLength(0);
  279. XPath xpath =
  280. handler.createXPath(exprBuffer.toString(), owner);
  281. m_parts.addElement(new AVTPartXPath(xpath));
  282. lookahead = null; // breaks out of inner while loop
  283. break;
  284. }
  285. default :
  286. {
  287. // part of the template stuff, just add it.
  288. exprBuffer.append(lookahead);
  289. lookahead = tokenizer.nextToken();
  290. }
  291. } // end inner switch
  292. } // end if lookahead length == 1
  293. else
  294. {
  295. // part of the template stuff, just add it.
  296. exprBuffer.append(lookahead);
  297. lookahead = tokenizer.nextToken();
  298. }
  299. } // end while(!lookahead.equals("}"))
  300. if (error != null)
  301. {
  302. break; // from inner while loop
  303. }
  304. }
  305. break;
  306. }
  307. catch (java.util.NoSuchElementException ex)
  308. {
  309. error = XSLMessages.createMessage(XSLTErrorResources.ER_ILLEGAL_ATTRIBUTE_VALUE, new Object[]{ name, stringedValue });
  310. break;
  311. }
  312. }
  313. case ('}') :
  314. {
  315. lookahead = tokenizer.nextToken();
  316. if (lookahead.equals("}"))
  317. {
  318. // Double curlys mean escape to show curly
  319. buffer.append(lookahead);
  320. lookahead = null; // swallow
  321. }
  322. else
  323. {
  324. // Illegal, I think...
  325. try
  326. {
  327. handler.warn(XSLTErrorResources.WG_FOUND_CURLYBRACE, null); //"Found \"}\" but no attribute template open!");
  328. }
  329. catch (org.xml.sax.SAXException se)
  330. {
  331. throw new TransformerException(se);
  332. }
  333. buffer.append("}");
  334. // leave the lookahead to be processed by the next round.
  335. }
  336. break;
  337. }
  338. default :
  339. {
  340. // Anything else just add to string.
  341. buffer.append(t);
  342. }
  343. } // end switch t
  344. } // end if length == 1
  345. else
  346. {
  347. // Anything else just add to string.
  348. buffer.append(t);
  349. }
  350. if (null != error)
  351. {
  352. try
  353. {
  354. handler.warn(XSLTErrorResources.WG_ATTR_TEMPLATE,
  355. new Object[]{ error }); //"Attr Template, "+error);
  356. }
  357. catch (org.xml.sax.SAXException se)
  358. {
  359. throw new TransformerException(se);
  360. }
  361. break;
  362. }
  363. } // end while(tokenizer.hasMoreTokens())
  364. if (buffer.length() > 0)
  365. {
  366. m_parts.addElement(new AVTPartSimple(buffer.toString()));
  367. buffer.setLength(0);
  368. }
  369. }
  370. finally
  371. {
  372. StringBufferPool.free(buffer);
  373. StringBufferPool.free(exprBuffer);
  374. }
  375. } // end else nTokens > 1
  376. if (null == m_parts && (null == m_simpleString))
  377. {
  378. // Error?
  379. m_simpleString = "";
  380. }
  381. }
  382. /**
  383. * Get the AVT as the original string.
  384. *
  385. * @return The AVT as the original string
  386. */
  387. public String getSimpleString()
  388. {
  389. if (null != m_simpleString)
  390. {
  391. return m_simpleString;
  392. }
  393. else if (null != m_parts)
  394. {
  395. FastStringBuffer buf = StringBufferPool.get();
  396. String s;
  397. try
  398. {
  399. buf.setLength(0);
  400. int n = m_parts.size();
  401. for (int i = 0; i < n; i++)
  402. {
  403. AVTPart part = (AVTPart) m_parts.elementAt(i);
  404. buf.append(part.getSimpleString());
  405. }
  406. s = buf.toString();
  407. }
  408. finally
  409. {
  410. StringBufferPool.free(buf);
  411. }
  412. return s;
  413. }
  414. else
  415. {
  416. return "";
  417. }
  418. }
  419. /**
  420. * Evaluate the AVT and return a String.
  421. *
  422. * @param xctxt Te XPathContext to use to evaluate this.
  423. * @param context The current source tree context.
  424. * @param nsNode The current namespace context (stylesheet tree context).
  425. * @param NodeList The current Context Node List.
  426. *
  427. * @return The AVT evaluated as a string
  428. *
  429. * @throws javax.xml.transform.TransformerException
  430. */
  431. public String evaluate(
  432. XPathContext xctxt, int context, org.apache.xml.utils.PrefixResolver nsNode)
  433. throws javax.xml.transform.TransformerException
  434. {
  435. FastStringBuffer buf = StringBufferPool.get();
  436. try
  437. {
  438. if (null != m_simpleString)
  439. {
  440. return m_simpleString;
  441. }
  442. else if (null != m_parts)
  443. {
  444. buf.setLength(0);
  445. int n = m_parts.size();
  446. for (int i = 0; i < n; i++)
  447. {
  448. AVTPart part = (AVTPart) m_parts.elementAt(i);
  449. part.evaluate(xctxt, buf, context, nsNode);
  450. }
  451. return buf.toString();
  452. }
  453. else
  454. {
  455. return "";
  456. }
  457. }
  458. finally
  459. {
  460. StringBufferPool.free(buf);
  461. }
  462. }
  463. /**
  464. * Test whether the AVT is insensitive to the context in which
  465. * it is being evaluated. This is intended to facilitate
  466. * compilation of templates, by allowing simple AVTs to be
  467. * converted back into strings.
  468. *
  469. * Currently the only case we recognize is simple strings.
  470. * ADDED 9/5/2000 to support compilation experiment
  471. *
  472. * @return True if the m_simpleString member of this AVT is not null
  473. */
  474. public boolean isContextInsensitive()
  475. {
  476. return null != m_simpleString;
  477. }
  478. /**
  479. * Tell if this expression or it's subexpressions can traverse outside
  480. * the current subtree.
  481. *
  482. * @return true if traversal outside the context node's subtree can occur.
  483. */
  484. public boolean canTraverseOutsideSubtree()
  485. {
  486. if (null != m_parts)
  487. {
  488. int n = m_parts.size();
  489. for (int i = 0; i < n; i++)
  490. {
  491. AVTPart part = (AVTPart) m_parts.elementAt(i);
  492. if (part.canTraverseOutsideSubtree())
  493. return true;
  494. }
  495. }
  496. return false;
  497. }
  498. /**
  499. * This function is used to fixup variables from QNames to stack frame
  500. * indexes at stylesheet build time.
  501. * @param vars List of QNames that correspond to variables. This list
  502. * should be searched backwards for the first qualified name that
  503. * corresponds to the variable reference qname. The position of the
  504. * QName in the vector from the start of the vector will be its position
  505. * in the stack frame (but variables above the globalsTop value will need
  506. * to be offset to the current stack frame).
  507. */
  508. public void fixupVariables(java.util.Vector vars, int globalsSize)
  509. {
  510. if (null != m_parts)
  511. {
  512. int n = m_parts.size();
  513. for (int i = 0; i < n; i++)
  514. {
  515. AVTPart part = (AVTPart) m_parts.elementAt(i);
  516. part.fixupVariables(vars, globalsSize);
  517. }
  518. }
  519. }
  520. /**
  521. * @see XSLTVisitable#callVisitors(XSLTVisitor)
  522. */
  523. public void callVisitors(XSLTVisitor visitor)
  524. {
  525. if(visitor.visitAVT(this) && (null != m_parts))
  526. {
  527. int n = m_parts.size();
  528. for (int i = 0; i < n; i++)
  529. {
  530. AVTPart part = (AVTPart) m_parts.elementAt(i);
  531. part.callVisitors(visitor);
  532. }
  533. }
  534. }
  535. /**
  536. * Returns true if this AVT is simple
  537. */
  538. public boolean isSimple() {
  539. return m_simpleString != null;
  540. }
  541. }