PageRenderTime 53ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/project/bridge/axiom/src/main/java/org/genxdm/bridge/axiom/AxiomModel.java

http://genxdm.googlecode.com/
Java | 1467 lines | 1335 code | 67 blank | 65 comment | 297 complexity | 36026cbeeea0fb5b25f6c039c9354896 MD5 | raw file
Possible License(s): Apache-2.0
  1. /*
  2. * Copyright (c) 2009-2011 TIBCO Software Inc.
  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. package org.genxdm.bridge.axiom;
  17. import java.net.URI;
  18. import java.util.ArrayList;
  19. import java.util.Collections;
  20. import java.util.HashMap;
  21. import java.util.Iterator;
  22. import java.util.LinkedList;
  23. import java.util.Map;
  24. import javax.xml.XMLConstants;
  25. import javax.xml.namespace.QName;
  26. import org.apache.axiom.om.OMAttribute;
  27. import org.apache.axiom.om.OMComment;
  28. import org.apache.axiom.om.OMContainer;
  29. import org.apache.axiom.om.OMDocument;
  30. import org.apache.axiom.om.OMElement;
  31. import org.apache.axiom.om.OMNamespace;
  32. import org.apache.axiom.om.OMNode;
  33. import org.apache.axiom.om.OMProcessingInstruction;
  34. import org.apache.axiom.om.OMText;
  35. import org.genxdm.Model;
  36. import org.genxdm.NodeKind;
  37. import org.genxdm.bridgekit.axes.IterableAncestorAxis;
  38. import org.genxdm.bridgekit.axes.IterableAncestorOrSelfAxis;
  39. import org.genxdm.bridgekit.axes.IterableChildAxis;
  40. import org.genxdm.bridgekit.axes.IterableChildAxisElements;
  41. import org.genxdm.bridgekit.axes.IterableChildAxisElementsByName;
  42. import org.genxdm.bridgekit.axes.IterableDescendantAxis;
  43. import org.genxdm.bridgekit.axes.IterableDescendantOrSelfAxis;
  44. import org.genxdm.bridgekit.axes.IterableFollowingAxis;
  45. import org.genxdm.bridgekit.axes.IterableFollowingSiblingAxis;
  46. import org.genxdm.bridgekit.axes.IterablePrecedingAxis;
  47. import org.genxdm.bridgekit.axes.IterablePrecedingSiblingAxis;
  48. import org.genxdm.bridgekit.names.QNameComparator;
  49. import org.genxdm.bridgekit.tree.Ordering;
  50. import org.genxdm.exceptions.GenXDMException;
  51. import org.genxdm.exceptions.PreCondition;
  52. import org.genxdm.io.ContentHandler;
  53. import org.genxdm.io.DtdAttributeKind;
  54. import org.genxdm.names.NamespaceBinding;
  55. public class AxiomModel
  56. implements Model<Object>
  57. {
  58. public int compare(Object one, Object two)
  59. {
  60. return Ordering.compareNodes(one, two, this);
  61. }
  62. public Iterable<Object> getAncestorAxis(Object node)
  63. {
  64. PreCondition.assertNotNull(node);
  65. return new IterableAncestorAxis<Object>(node, this);
  66. }
  67. public Iterable<Object> getAncestorOrSelfAxis(Object node)
  68. {
  69. PreCondition.assertNotNull(node);
  70. return new IterableAncestorOrSelfAxis<Object>(node, this);
  71. }
  72. public OMAttribute getAttribute(final Object parent, final String namespaceURI, final String localName)
  73. {
  74. final OMElement element = AxiomSupport.dynamicDowncastElement(parent);
  75. if (null != element)
  76. {
  77. return element.getAttribute(new QName(namespaceURI.toString(), localName.toString()));
  78. }
  79. else
  80. {
  81. return null;
  82. }
  83. }
  84. public Iterable<Object> getAttributeAxis(final Object node, final boolean inherit)
  85. {
  86. PreCondition.assertNotNull(node);
  87. final OMElement element = AxiomSupport.dynamicDowncastElement(node);
  88. if (element != null)
  89. {
  90. boolean hasLang = false;
  91. boolean hasSpace = false;
  92. boolean hasBase = false;
  93. final ArrayList<Object> attributes = new ArrayList<Object>();
  94. @SuppressWarnings("unchecked")
  95. final Iterator<OMAttribute> it = element.getAllAttributes();
  96. while (it.hasNext())
  97. {
  98. OMAttribute a = it.next();
  99. attributes.add(a);
  100. if (inherit)
  101. {
  102. QName n = a.getQName();
  103. if (n.getNamespaceURI().equals(XMLConstants.XML_NS_URI))
  104. {
  105. String l = n.getLocalPart();
  106. if (l.equals("lang"))
  107. hasLang = true;
  108. else if (l.equals("space"))
  109. hasSpace = true;
  110. else if (l.equals("base"))
  111. hasBase = true;
  112. }
  113. }
  114. }
  115. if (inherit)
  116. {
  117. OMContainer parent = element;
  118. do {
  119. parent = getParent(parent);
  120. if ( (parent != null) && (parent instanceof OMElement) )
  121. {
  122. Iterable<Object> parentAtts = getAttributeAxis(parent, false);
  123. for (Object o : parentAtts)
  124. {
  125. OMAttribute a = AxiomSupport.dynamicDowncastAttribute(o);
  126. QName aName = a.getQName();
  127. if (aName.getNamespaceURI().equals(XMLConstants.XML_NS_URI))
  128. {
  129. // TODO: should these be new faux attributes?
  130. String n = aName.getLocalPart();
  131. if (n.equals("lang") && !hasLang)
  132. {
  133. attributes.add(a);
  134. hasLang = true;
  135. }
  136. else if (n.equals("space") && !hasSpace)
  137. {
  138. attributes.add(a);
  139. hasSpace = true;
  140. }
  141. else if (n.equals("base") && !hasBase)
  142. {
  143. attributes.add(a);
  144. hasBase = true;
  145. }
  146. }
  147. }
  148. }
  149. } while (parent != null);
  150. }
  151. return attributes; // enhanced with scoped atts if inherit == true, otherwise not
  152. }
  153. return Collections.emptyList();
  154. }
  155. public Iterable<QName> getAttributeNames(final Object node, final boolean orderCanonical)
  156. {
  157. final OMElement element = AxiomSupport.dynamicDowncastElement(node);
  158. if (element != null)
  159. {
  160. final ArrayList<QName> names = new ArrayList<QName>();
  161. @SuppressWarnings("unchecked")
  162. final Iterator<OMAttribute> it = element.getAllAttributes();
  163. while (it.hasNext())
  164. {
  165. names.add(it.next().getQName());
  166. }
  167. if (orderCanonical)
  168. {
  169. Collections.sort(names, new QNameComparator());
  170. }
  171. return names;
  172. }
  173. return null;
  174. }
  175. public String getAttributeStringValue(Object parent, String namespaceURI, String localName)
  176. {
  177. OMAttribute attribute = getAttribute(parent, namespaceURI, localName);
  178. if (attribute != null)
  179. return attribute.getAttributeValue();
  180. return null;
  181. }
  182. public URI getBaseURI(final Object node)
  183. {
  184. // TODO: resolve this problem.
  185. // axiom doesn't support XML:Base, it appears.
  186. return null;
  187. }
  188. public Iterable<Object> getChildAxis(Object node)
  189. {
  190. if (node != null)
  191. return new IterableChildAxis<Object>(node, this);
  192. return null;
  193. }
  194. public Iterable<Object> getChildElements(Object node)
  195. {
  196. if (node != null)
  197. return new IterableChildAxisElements<Object>(node, this);
  198. return null;
  199. }
  200. public Iterable<Object> getChildElementsByName(final Object node, final String namespaceURI, final String localName)
  201. {
  202. if (null != node)
  203. {
  204. return new IterableChildAxisElementsByName<Object>(node, namespaceURI, localName, this);
  205. }
  206. else
  207. {
  208. return Collections.emptyList();
  209. }
  210. }
  211. public Iterable<Object> getDescendantAxis(Object node)
  212. {
  213. if (node != null)
  214. return new IterableDescendantAxis<Object>(node, this);
  215. return null;
  216. }
  217. public Iterable<Object> getDescendantOrSelfAxis(Object node)
  218. {
  219. if (node != null)
  220. return new IterableDescendantOrSelfAxis<Object>(node, this);
  221. return null;
  222. }
  223. public URI getDocumentURI(final Object node)
  224. {
  225. // TODO: resolve missing axiom functionality
  226. return null;
  227. }
  228. public OMElement getElementById(final Object context, final String id)
  229. {
  230. // note: this depends upon the map having been initialized.
  231. // TODO: check the size of the map? if it's empty, we might want
  232. // to try to look through the document for ids. barf-puke, but eh.
  233. Map<String, OMElement> idMap = AxiomSupport.getIdMap(AxiomSupport.dynamicDowncastDocument(getRoot(context)));
  234. return idMap.get(id);
  235. }
  236. public OMNode getFirstChild(final Object origin)
  237. {
  238. final OMContainer container = AxiomSupport.dynamicDowncastContainer(origin);
  239. if (null != container)
  240. {
  241. return container.getFirstOMChild();
  242. }
  243. else
  244. {
  245. return null;
  246. }
  247. }
  248. public OMElement getFirstChildElement(final Object origin)
  249. {
  250. // it's probably an element container
  251. final OMElement element = AxiomSupport.dynamicDowncastElement(origin);
  252. if (element != null)
  253. {
  254. return element.getFirstElement();
  255. }
  256. else
  257. {
  258. // but it might be a document (nothing but documents and elements contain elements)
  259. final OMDocument document = AxiomSupport.dynamicDowncastDocument(origin);
  260. if (document != null)
  261. {
  262. return document.getOMDocumentElement();
  263. }
  264. }
  265. return null;
  266. }
  267. public OMElement getFirstChildElementByName(Object node, String namespaceURI, String localName)
  268. {
  269. final OMContainer container = AxiomSupport.dynamicDowncastContainer(node);
  270. if (container != null)
  271. {
  272. final QName name = new QName(namespaceURI, localName);
  273. return container.getFirstChildWithName(name);
  274. }
  275. return null;
  276. }
  277. public Iterable<Object> getFollowingAxis(Object node)
  278. {
  279. if (node != null)
  280. return new IterableFollowingAxis<Object>(node, this);
  281. return null;
  282. }
  283. public Iterable<Object> getFollowingSiblingAxis(Object node)
  284. {
  285. if (node != null)
  286. return new IterableFollowingSiblingAxis<Object>(node, this);
  287. return null;
  288. }
  289. public OMNode getLastChild(final Object origin)
  290. {
  291. final OMContainer container = AxiomSupport.dynamicDowncastContainer(origin);
  292. if (null != container)
  293. {
  294. Object lastChild = null;
  295. final Iterator<?> children = container.getChildren();
  296. while (children.hasNext())
  297. {
  298. lastChild = children.next();
  299. }
  300. return ((OMNode)lastChild);
  301. }
  302. else
  303. {
  304. return null;
  305. }
  306. }
  307. public String getLocalName(Object node)
  308. {
  309. {
  310. final OMElement element = AxiomSupport.dynamicDowncastElement(node);
  311. if (null != element)
  312. {
  313. return element.getLocalName();
  314. }
  315. }
  316. {
  317. final OMAttribute attribute = AxiomSupport.dynamicDowncastAttribute(node);
  318. if (null != attribute)
  319. {
  320. return attribute.getLocalName();
  321. }
  322. }
  323. {
  324. final OMNamespace namespace = AxiomSupport.dynamicDowncastNamespace(node);
  325. if (null != namespace)
  326. {
  327. return namespace.getPrefix();
  328. }
  329. }
  330. {
  331. final OMProcessingInstruction pi = AxiomSupport.dynamicDowncastProcessingInstruction(node);
  332. if (null != pi)
  333. {
  334. return pi.getTarget();
  335. }
  336. }
  337. switch (AxiomSupport.getNodeKind(node))
  338. {
  339. case DOCUMENT:
  340. case COMMENT:
  341. case TEXT:
  342. {
  343. return null;
  344. }
  345. default:
  346. {
  347. throw new AssertionError(AxiomSupport.getNodeKind(node));
  348. }
  349. }
  350. }
  351. public Iterable<Object> getNamespaceAxis(final Object node, final boolean inherit)
  352. {
  353. PreCondition.assertNotNull(node);
  354. final OMElement origin = AxiomSupport.dynamicDowncastElement(node);
  355. if (origin != null)
  356. {
  357. if (inherit)
  358. {
  359. return getNamespacesInScope(origin);
  360. }
  361. else
  362. {
  363. return getNamespaces(origin);
  364. }
  365. }
  366. return Collections.emptyList();
  367. }
  368. public Iterable<NamespaceBinding> getNamespaceBindings(final Object node)
  369. {
  370. // TODO: review this for correctness?
  371. final OMElement element = AxiomSupport.dynamicDowncastElement(node);
  372. if (null != element)
  373. {
  374. /**
  375. * Axiom's getAllDeclaredNamespaces method returns only those prefix mappings that are declared locally. This is what we want for this method. However, it also returns a prefix mapping, ""=>"", even if this has not been explicitly declared. There is no way
  376. * of telling whether it is explicitly declared or implicitly added by the Axiom implementation. We can remove it but should also check first to see if it is being added as a cancellation. The alternative may be to have all implementations return this
  377. * mapping if the element is in the global namespace.
  378. */
  379. @SuppressWarnings("unchecked")
  380. final Iterator<OMNamespace> namespaces = element.getAllDeclaredNamespaces();
  381. if (namespaces.hasNext())
  382. {
  383. final ArrayList<NamespaceBinding> names = new ArrayList<NamespaceBinding>();
  384. while (namespaces.hasNext())
  385. {
  386. final OMNamespace namespace = namespaces.next();
  387. final String prefix = namespace.getPrefix();
  388. final String uri = namespace.getNamespaceURI();
  389. if (uri.length() == 0 && prefix.length() == 0)
  390. {
  391. if (isNamespaceCancellationRequired(element))
  392. {
  393. names.add(new NamespaceBinding()
  394. {
  395. public String getNamespaceURI()
  396. {
  397. return uri;
  398. }
  399. public String getPrefix()
  400. {
  401. return XMLConstants.DEFAULT_NS_PREFIX;
  402. }
  403. });
  404. }
  405. }
  406. else
  407. {
  408. names.add(new NamespaceBinding()
  409. {
  410. public String getNamespaceURI()
  411. {
  412. return uri;
  413. }
  414. public String getPrefix()
  415. {
  416. return prefix;
  417. }
  418. });
  419. }
  420. }
  421. return names;
  422. }
  423. else
  424. {
  425. return Collections.emptyList();
  426. }
  427. }
  428. else
  429. {
  430. return Collections.emptyList();
  431. }
  432. }
  433. public String getNamespaceForPrefix(final Object node, final String prefix)
  434. {
  435. for (NamespaceBinding binding : getNamespaceBindings(node))
  436. {
  437. if (binding.getPrefix().equals(prefix))
  438. return binding.getNamespaceURI();
  439. }
  440. return null;
  441. }
  442. public Iterable<String> getNamespaceNames(final Object node, final boolean orderCanonical)
  443. {
  444. final OMElement element = AxiomSupport.dynamicDowncastElement(node);
  445. if (null != element)
  446. {
  447. final ArrayList<String> names = new ArrayList<String>();
  448. for (Object ns : getNamespaces(element))
  449. {
  450. OMNamespace namespace = AxiomSupport.dynamicDowncastFauxNamespace(ns);
  451. final String prefix = namespace.getPrefix();
  452. final String uri = namespace.getNamespaceURI();
  453. if (uri.length() == 0 && prefix.length() == 0)
  454. {
  455. if (isNamespaceCancellationRequired(element))
  456. {
  457. names.add(XMLConstants.DEFAULT_NS_PREFIX);
  458. }
  459. }
  460. else
  461. {
  462. if (isNamespaceDeclarationRequired(prefix, uri, element))
  463. {
  464. names.add(prefix);
  465. }
  466. }
  467. }
  468. if (orderCanonical)
  469. {
  470. Collections.sort(names);
  471. }
  472. if (names.size() > 0)
  473. return names;
  474. }
  475. return Collections.emptyList();
  476. }
  477. public Iterable<Object> getNamespaces(final OMElement element)
  478. {
  479. @SuppressWarnings("unchecked")
  480. final Iterator<OMNamespace> it = element.getAllDeclaredNamespaces();
  481. if (it.hasNext())
  482. {
  483. final ArrayList<Object> namespaces = new ArrayList<Object>();
  484. while (it.hasNext())
  485. {
  486. final OMNamespace namespace = it.next();
  487. final String prefix = namespace.getPrefix();
  488. final String uri = namespace.getNamespaceURI();
  489. if (uri.length() == 0 && prefix.length() == 0)
  490. {
  491. if (isNamespaceCancellationRequired(element))
  492. {
  493. namespaces.add(new FauxNamespace(namespace, element));
  494. }
  495. }
  496. else
  497. {
  498. // ignore the xml namespace
  499. if (!prefix.equals("xml"))
  500. namespaces.add(new FauxNamespace(namespace, element));
  501. }
  502. }
  503. return namespaces;
  504. }
  505. else
  506. {
  507. return Collections.emptyList();
  508. }
  509. }
  510. public Iterable<Object> getNamespacesInScope(final OMElement element)
  511. {
  512. final LinkedList<OMElement> chain = new LinkedList<OMElement>();
  513. OMElement ancestorOrSelf = element;
  514. while (null != ancestorOrSelf)
  515. {
  516. chain.addFirst(ancestorOrSelf);
  517. ancestorOrSelf = AxiomSupport.dynamicDowncastElement(ancestorOrSelf.getParent());
  518. }
  519. final Map<String, Object> namespaces = new HashMap<String, Object>();
  520. for (final OMElement link : chain)
  521. {
  522. @SuppressWarnings("unchecked")
  523. final Iterator<OMNamespace> it = link.getAllDeclaredNamespaces();
  524. while (it.hasNext())
  525. {
  526. final OMNamespace namespace = it.next();
  527. final String prefix = namespace.getPrefix();
  528. final String uri = namespace.getNamespaceURI();
  529. if (uri.length() == 0 && prefix.length() == 0)
  530. {
  531. if (namespaces.containsKey(prefix))
  532. {
  533. namespaces.remove(prefix);
  534. }
  535. }
  536. else
  537. {
  538. namespaces.put(prefix, new FauxNamespace(namespace, element));
  539. }
  540. }
  541. }
  542. namespaces.put(XMLConstants.XML_NS_PREFIX, new FauxNamespace(XMLConstants.XML_NS_PREFIX, XMLConstants.XML_NS_URI, (OMContainer)getRoot(element)));
  543. return namespaces.values();
  544. }
  545. public String getNamespaceURI(Object node)
  546. {
  547. {
  548. final OMElement element = AxiomSupport.dynamicDowncastElement(node);
  549. if (null != element)
  550. {
  551. // namespace may be null.
  552. if (element.getNamespace() == null)
  553. {
  554. return XMLConstants.NULL_NS_URI;
  555. }
  556. return element.getNamespace().getNamespaceURI();
  557. }
  558. }
  559. {
  560. final OMNamespace namespace = AxiomSupport.dynamicDowncastNamespace(node);
  561. if (null != namespace)
  562. {
  563. return XMLConstants.NULL_NS_URI;
  564. }
  565. }
  566. {
  567. final OMAttribute attribute = AxiomSupport.dynamicDowncastAttribute(node);
  568. if (null != attribute)
  569. {
  570. OMNamespace ns = attribute.getNamespace();
  571. if (ns == null)
  572. return "";
  573. return ns.getNamespaceURI();
  574. }
  575. }
  576. NodeKind kind = AxiomSupport.getNodeKind(node);
  577. if (kind != null) {
  578. switch (kind)
  579. {
  580. case DOCUMENT:
  581. case COMMENT:
  582. case TEXT:
  583. {
  584. return null;
  585. }
  586. case PROCESSING_INSTRUCTION:
  587. {
  588. return XMLConstants.NULL_NS_URI;
  589. }
  590. default:
  591. {
  592. throw new AssertionError(AxiomSupport.getNodeKind(node));
  593. }
  594. }
  595. }
  596. return null;
  597. }
  598. public OMNode getNextSibling(final Object origin)
  599. {
  600. final OMNode node = AxiomSupport.dynamicDowncastNode(origin);
  601. if (null != node)
  602. {
  603. return node.getNextOMSibling();
  604. }
  605. else
  606. {
  607. // It could be document, attribute or namespace which aren't OMNode
  608. // and also don't have the concept of siblings.
  609. return null;
  610. }
  611. }
  612. public OMElement getNextSiblingElement(Object node)
  613. {
  614. return getNextSiblingElementByName(node, null, null);
  615. }
  616. public OMElement getNextSiblingElementByName(Object node, String namespaceURI, String localName)
  617. {
  618. OMNode nodely = AxiomSupport.dynamicDowncastNode(node);
  619. if (nodely != null)
  620. {
  621. OMNode next = nodely.getNextOMSibling();
  622. while (next != null) {
  623. if (matches(next, NodeKind.ELEMENT, namespaceURI, localName))
  624. {
  625. return (OMElement)next;
  626. }
  627. next = next.getNextOMSibling();
  628. }
  629. }
  630. // TODO: just guessing that if you want a sibling element, you've got an element.
  631. // however, this may not be true, so we may need to enhance the else, here.
  632. return null;
  633. }
  634. public NodeKind getNodeKind(final Object origin)
  635. {
  636. return AxiomSupport.getNodeKind(origin);
  637. }
  638. public OMContainer getParent(final Object origin)
  639. {
  640. return AxiomSupport.getParent(origin);
  641. }
  642. public Iterable<Object> getPrecedingAxis(Object node)
  643. {
  644. if (node != null)
  645. return new IterablePrecedingAxis<Object>(node, this);
  646. return null;
  647. }
  648. public Iterable<Object> getPrecedingSiblingAxis(Object node)
  649. {
  650. if (node != null)
  651. return new IterablePrecedingSiblingAxis<Object>(node, this);
  652. return null;
  653. }
  654. public String getPrefix(final Object node)
  655. {
  656. {
  657. final OMElement element = AxiomSupport.dynamicDowncastElement(node);
  658. if (null != element)
  659. {
  660. // namespace may be null
  661. if (element.getNamespace() == null)
  662. {
  663. return XMLConstants.DEFAULT_NS_PREFIX;
  664. }
  665. return element.getNamespace().getPrefix();
  666. }
  667. }
  668. {
  669. final OMAttribute attribute = AxiomSupport.dynamicDowncastAttribute(node);
  670. if (null != attribute)
  671. {
  672. OMNamespace ns = attribute.getNamespace();
  673. if (ns == null)
  674. return "";
  675. return ns.getPrefix();
  676. }
  677. }
  678. {
  679. final OMNamespace namespace = AxiomSupport.dynamicDowncastNamespace(node);
  680. if (null != namespace)
  681. {
  682. // "getPrefix()" is absolutely *wrong*.
  683. return XMLConstants.DEFAULT_NS_PREFIX;
  684. }
  685. }
  686. switch (AxiomSupport.getNodeKind(node))
  687. {
  688. case DOCUMENT:
  689. case COMMENT:
  690. case TEXT:
  691. {
  692. return null;
  693. }
  694. case PROCESSING_INSTRUCTION:
  695. {
  696. return XMLConstants.DEFAULT_NS_PREFIX;
  697. }
  698. default:
  699. {
  700. throw new AssertionError(AxiomSupport.getNodeKind(node));
  701. }
  702. }
  703. }
  704. public OMNode getPreviousSibling(final Object origin)
  705. {
  706. final OMDocument document = AxiomSupport.dynamicDowncastDocument(origin);
  707. if (null != document)
  708. {
  709. return null;
  710. }
  711. else
  712. {
  713. final OMNode node = AxiomSupport.dynamicDowncastNode(origin);
  714. if (null != node)
  715. {
  716. final OMNode previous = node.getPreviousOMSibling();
  717. if (node == previous)
  718. {
  719. // This is clearly a bug
  720. return null;
  721. }
  722. else
  723. {
  724. return previous;
  725. }
  726. }
  727. else
  728. {
  729. // It could be attribute or namespace which aren't OMNode
  730. // and also don't have the concept of siblings.
  731. return null;
  732. }
  733. }
  734. }
  735. public Object getRoot(final Object origin)
  736. {
  737. final OMContainer x = AxiomSupport.getParent(origin);
  738. if (x == null)
  739. {
  740. return origin;
  741. }
  742. else
  743. {
  744. return getRoot(x);
  745. }
  746. }
  747. public String getStringValue(final Object node)
  748. {
  749. {
  750. final OMContainer container = AxiomSupport.dynamicDowncastContainer(node);
  751. if (null != container)
  752. {
  753. @SuppressWarnings("unchecked")
  754. final Iterator<OMNode> children = container.getChildren();
  755. String first = null;
  756. if (children.hasNext())
  757. {
  758. final OMNode child = children.next();
  759. switch (getNodeKind(child))
  760. {
  761. case ELEMENT:
  762. {
  763. first = getStringValue(child);
  764. }
  765. break;
  766. case TEXT:
  767. {
  768. first = ((OMText)child).getText();
  769. }
  770. break;
  771. case COMMENT:
  772. {
  773. // Ignore
  774. }
  775. break;
  776. default:
  777. {
  778. throw new AssertionError(getNodeKind(child));
  779. }
  780. }
  781. }
  782. if (children.hasNext())
  783. {
  784. final StringBuilder sb = new StringBuilder();
  785. if (null != first)
  786. {
  787. sb.append(first);
  788. }
  789. while (children.hasNext())
  790. {
  791. final OMNode child = children.next();
  792. switch (getNodeKind(child))
  793. {
  794. case ELEMENT:
  795. {
  796. sb.append(getStringValue(child));
  797. }
  798. break;
  799. case TEXT:
  800. {
  801. sb.append(((OMText)child).getText());
  802. }
  803. case COMMENT:
  804. case PROCESSING_INSTRUCTION:
  805. {
  806. // Ignore
  807. }
  808. break;
  809. default:
  810. {
  811. throw new AssertionError(getNodeKind(child));
  812. }
  813. }
  814. }
  815. return sb.toString();
  816. }
  817. else
  818. {
  819. return (null != first) ? first : "";
  820. }
  821. }
  822. }
  823. {
  824. final OMText text = AxiomSupport.dynamicDowncastText(node);
  825. if (null != text)
  826. {
  827. return text.getText();
  828. }
  829. }
  830. {
  831. final OMAttribute attribute = AxiomSupport.dynamicDowncastAttribute(node);
  832. if (null != attribute)
  833. {
  834. return attribute.getAttributeValue();
  835. }
  836. }
  837. {
  838. final OMNamespace namespace = AxiomSupport.dynamicDowncastNamespace(node);
  839. if (null != namespace)
  840. {
  841. return namespace.getNamespaceURI();
  842. }
  843. }
  844. {
  845. final OMProcessingInstruction pi = AxiomSupport.dynamicDowncastProcessingInstruction(node);
  846. if (null != pi)
  847. {
  848. return pi.getValue();
  849. }
  850. }
  851. {
  852. final OMComment comment = AxiomSupport.dynamicDowncastComment(node);
  853. if (null != comment)
  854. {
  855. return comment.getValue();
  856. }
  857. }
  858. throw new AssertionError("getStringValue(" + node + ")");
  859. }
  860. public boolean hasAttributes(final Object node)
  861. {
  862. final OMElement element = AxiomSupport.dynamicDowncastElement(node);
  863. if (null != element)
  864. {
  865. return element.getAllAttributes().hasNext();
  866. }
  867. else
  868. {
  869. return false;
  870. }
  871. }
  872. public boolean hasChildren(final Object node)
  873. {
  874. final OMContainer container = AxiomSupport.dynamicDowncastContainer(node);
  875. if (null != container)
  876. {
  877. return container.getChildren().hasNext();
  878. }
  879. else
  880. {
  881. return false;
  882. }
  883. }
  884. public boolean hasNamespaces(final Object node)
  885. {
  886. final OMElement element = AxiomSupport.dynamicDowncastElement(node);
  887. if (null != element)
  888. {
  889. @SuppressWarnings("unchecked")
  890. final Iterator<OMNamespace> namespaces = element.getAllDeclaredNamespaces();
  891. while (namespaces.hasNext())
  892. {
  893. // oh, axiom, shame on you!
  894. // the default namespace is reported as "declared"
  895. OMNamespace ns = (OMNamespace)namespaces.next();
  896. if (! (ns.getPrefix().equals("") && ns.getNamespaceURI().equals("")) )
  897. return true;
  898. }
  899. return false;
  900. }
  901. else
  902. {
  903. return false;
  904. }
  905. }
  906. public boolean hasNextSibling(final Object node)
  907. {
  908. {
  909. final OMElement element = AxiomSupport.dynamicDowncastElement(node);
  910. {
  911. if (null != element)
  912. {
  913. return element.getNextOMSibling() != null;
  914. }
  915. }
  916. }
  917. {
  918. final OMText text = AxiomSupport.dynamicDowncastText(node);
  919. {
  920. if (null != text)
  921. {
  922. return text.getNextOMSibling() != null;
  923. }
  924. }
  925. }
  926. {
  927. final OMAttribute attribute = AxiomSupport.dynamicDowncastAttribute(node);
  928. {
  929. if (null != attribute)
  930. {
  931. return false;
  932. }
  933. }
  934. }
  935. {
  936. final OMNamespace namespace = AxiomSupport.dynamicDowncastNamespace(node);
  937. {
  938. if (null != namespace)
  939. {
  940. return false;
  941. }
  942. }
  943. }
  944. {
  945. final OMDocument document = AxiomSupport.dynamicDowncastDocument(node);
  946. {
  947. if (null != document)
  948. {
  949. return false;
  950. }
  951. }
  952. }
  953. {
  954. final OMComment comment = AxiomSupport.dynamicDowncastComment(node);
  955. {
  956. if (null != comment)
  957. {
  958. return comment.getNextOMSibling() != null;
  959. }
  960. }
  961. }
  962. {
  963. final OMProcessingInstruction pi = AxiomSupport.dynamicDowncastProcessingInstruction(node);
  964. {
  965. if (null != pi)
  966. {
  967. return pi.getNextOMSibling() != null;
  968. }
  969. }
  970. }
  971. throw new AssertionError("hasNextSibling(" + node + ")");
  972. }
  973. public boolean hasParent(final Object node)
  974. {
  975. {
  976. final OMElement element = AxiomSupport.dynamicDowncastElement(node);
  977. if (null != element)
  978. {
  979. return (null != element.getParent());
  980. }
  981. }
  982. {
  983. final OMText text = AxiomSupport.dynamicDowncastText(node);
  984. if (null != text)
  985. {
  986. return (null != text.getParent());
  987. }
  988. }
  989. {
  990. final OMAttribute attribute = AxiomSupport.dynamicDowncastAttribute(node);
  991. {
  992. if (null != attribute)
  993. {
  994. return attribute.getOwner() != null;
  995. }
  996. }
  997. }
  998. {
  999. final FauxNamespace namespace = AxiomSupport.dynamicDowncastFauxNamespace(node);
  1000. if (null != namespace)
  1001. {
  1002. return namespace.getParent() != null;
  1003. }
  1004. }
  1005. {
  1006. final OMNamespace namespace = AxiomSupport.dynamicDowncastNamespace(node);
  1007. if (null != namespace)
  1008. {
  1009. return false;
  1010. }
  1011. }
  1012. if (null != AxiomSupport.dynamicDowncastDocument(node))
  1013. {
  1014. return false;
  1015. }
  1016. {
  1017. final OMProcessingInstruction pi = AxiomSupport.dynamicDowncastProcessingInstruction(node);
  1018. if (null != pi)
  1019. {
  1020. return (null != pi.getParent());
  1021. }
  1022. }
  1023. {
  1024. final OMComment comment = AxiomSupport.dynamicDowncastComment(node);
  1025. if (null != comment)
  1026. {
  1027. return (null != comment.getParent());
  1028. }
  1029. }
  1030. throw new AssertionError("hasParent(" + node + ")");
  1031. }
  1032. public boolean hasPreviousSibling(final Object node)
  1033. {
  1034. {
  1035. final OMElement element = AxiomSupport.dynamicDowncastElement(node);
  1036. {
  1037. if (null != element)
  1038. {
  1039. return element.getPreviousOMSibling() != null;
  1040. }
  1041. }
  1042. }
  1043. {
  1044. final OMText text = AxiomSupport.dynamicDowncastText(node);
  1045. {
  1046. if (null != text)
  1047. {
  1048. return text.getPreviousOMSibling() != null;
  1049. }
  1050. }
  1051. }
  1052. {
  1053. final OMAttribute attribute = AxiomSupport.dynamicDowncastAttribute(node);
  1054. {
  1055. if (null != attribute)
  1056. {
  1057. return false;
  1058. }
  1059. }
  1060. }
  1061. {
  1062. final OMNamespace namespace = AxiomSupport.dynamicDowncastNamespace(node);
  1063. {
  1064. if (null != namespace)
  1065. {
  1066. return false;
  1067. }
  1068. }
  1069. }
  1070. {
  1071. final OMDocument document = AxiomSupport.dynamicDowncastDocument(node);
  1072. {
  1073. if (null != document)
  1074. {
  1075. return false;
  1076. }
  1077. }
  1078. }
  1079. {
  1080. final OMComment comment = AxiomSupport.dynamicDowncastComment(node);
  1081. {
  1082. if (null != comment)
  1083. {
  1084. return comment.getPreviousOMSibling() != null;
  1085. }
  1086. }
  1087. }
  1088. {
  1089. final OMProcessingInstruction pi = AxiomSupport.dynamicDowncastProcessingInstruction(node);
  1090. {
  1091. if (null != pi)
  1092. {
  1093. return pi.getPreviousOMSibling() != null;
  1094. }
  1095. }
  1096. }
  1097. throw new AssertionError("hasPreviousSibling(" + node + ")");
  1098. }
  1099. public boolean isAttribute(final Object node)
  1100. {
  1101. if (null != AxiomSupport.dynamicDowncastAttribute(node))
  1102. {
  1103. return true;
  1104. }
  1105. else
  1106. {
  1107. return false;
  1108. }
  1109. }
  1110. public boolean isElement(final Object node)
  1111. {
  1112. if (null != AxiomSupport.dynamicDowncastElement(node))
  1113. {
  1114. return true;
  1115. }
  1116. else
  1117. {
  1118. return false;
  1119. }
  1120. }
  1121. public boolean isNamespace(final Object node)
  1122. {
  1123. if (null != AxiomSupport.dynamicDowncastNamespace(node))
  1124. {
  1125. return true;
  1126. }
  1127. else
  1128. {
  1129. return false;
  1130. }
  1131. }
  1132. public boolean isId(final Object node)
  1133. {
  1134. if (isAttribute(node))
  1135. {
  1136. OMAttribute att = AxiomSupport.dynamicDowncastAttribute(node);
  1137. if (att.getAttributeType().equals("ID")) return true;
  1138. if (att.getNamespace().getNamespaceURI().equals(XMLConstants.XML_NS_URI) &&
  1139. att.getLocalName().equals("id"))
  1140. return true;
  1141. }
  1142. if (isElement(node))
  1143. {
  1144. for (Object o : getAttributeAxis(node, false))
  1145. {
  1146. if (isId(o)) return true;
  1147. }
  1148. }
  1149. // falls through, if you weren't paying attention.
  1150. return false;
  1151. }
  1152. public boolean isIdRefs(final Object node)
  1153. {
  1154. if (isAttribute(node))
  1155. {
  1156. OMAttribute att = AxiomSupport.dynamicDowncastAttribute(node);
  1157. return att.getAttributeType().startsWith("IDREF");
  1158. }
  1159. if (isElement(node))
  1160. {
  1161. for (Object o : getAttributeAxis(node, false))
  1162. {
  1163. if (isIdRefs(o)) return true;
  1164. }
  1165. }
  1166. return false;
  1167. }
  1168. public Object getNodeId(final Object node)
  1169. {
  1170. if (node instanceof OMAttribute)
  1171. return new AttributeIdentity((OMAttribute)node);
  1172. if (node instanceof OMNamespace)
  1173. return new NamespaceIdentity((OMNamespace)node);
  1174. return node;
  1175. }
  1176. public boolean isText(final Object node)
  1177. {
  1178. if (null != AxiomSupport.dynamicDowncastText(node))
  1179. {
  1180. return true;
  1181. }
  1182. else
  1183. {
  1184. return false;
  1185. }
  1186. }
  1187. public boolean matches(Object node, NodeKind nodeKind, String namespaceURI, String localName)
  1188. {
  1189. if (nodeKind != null)
  1190. {
  1191. if (getNodeKind(node) != nodeKind)
  1192. {
  1193. return false;
  1194. }
  1195. }
  1196. return matches(node, namespaceURI, localName);
  1197. }
  1198. public boolean matches(final Object node, final String namespaceArg, final String localNameArg)
  1199. {
  1200. if (namespaceArg != null)
  1201. {
  1202. final String namespace = getNamespaceURI(node);
  1203. if (null != namespace)
  1204. {
  1205. if (!namespaceArg.equals(namespace))
  1206. {
  1207. return false;
  1208. }
  1209. }
  1210. else
  1211. {
  1212. return false;
  1213. }
  1214. }
  1215. if (localNameArg != null)
  1216. {
  1217. final String localName = getLocalName(node);
  1218. if (null != localName)
  1219. {
  1220. if (!localNameArg.equals(localName))
  1221. {
  1222. return false;
  1223. }
  1224. }
  1225. else
  1226. {
  1227. return false;
  1228. }
  1229. }
  1230. return true;
  1231. }
  1232. @SuppressWarnings("rawtypes")
  1233. public void stream(Object node, boolean copyNamespaces, ContentHandler handler)
  1234. throws GenXDMException
  1235. {
  1236. switch (getNodeKind(node))
  1237. {
  1238. case ELEMENT:
  1239. {
  1240. OMElement element = AxiomSupport.dynamicDowncastElement(node);
  1241. handler.startElement(element.getQName().getNamespaceURI(), element.getQName().getLocalPart(), element.getQName().getPrefix());
  1242. if (hasNamespaces(node))
  1243. {
  1244. Iterator it = element.getAllDeclaredNamespaces();
  1245. while (it.hasNext())
  1246. {
  1247. stream(it.next(), copyNamespaces, handler);
  1248. }
  1249. }
  1250. if (hasAttributes(node))
  1251. {
  1252. Iterator it = element.getAllAttributes();
  1253. while (it.hasNext())
  1254. {
  1255. stream(it.next(), copyNamespaces, handler);
  1256. }
  1257. }
  1258. if (hasChildren(node))
  1259. {
  1260. Iterator it = element.getChildren();
  1261. while (it.hasNext())
  1262. {
  1263. stream(it.next(), copyNamespaces, handler);
  1264. }
  1265. }
  1266. handler.endElement();
  1267. }
  1268. break;
  1269. case ATTRIBUTE:
  1270. {
  1271. OMAttribute attribute = AxiomSupport.dynamicDowncastAttribute(node);
  1272. final String prefix = copyNamespaces ? attribute.getQName().getPrefix() : "";
  1273. handler.attribute(attribute.getQName().getNamespaceURI(), attribute.getQName().getLocalPart(), prefix, attribute.getAttributeValue(), DtdAttributeKind.get(attribute.getAttributeType()));
  1274. }
  1275. break;
  1276. case TEXT:
  1277. {
  1278. OMText text = AxiomSupport.dynamicDowncastText(node);
  1279. handler.text(text.getText());
  1280. }
  1281. break;
  1282. case DOCUMENT:
  1283. {
  1284. OMDocument doc = AxiomSupport.dynamicDowncastDocument(node);
  1285. // TODO: i don't think that this is quite right.
  1286. handler.startDocument(getDocumentURI(node), "");
  1287. Iterator it = doc.getChildren();
  1288. while (it.hasNext())
  1289. {
  1290. stream(it.next(), copyNamespaces, handler);
  1291. }
  1292. handler.endDocument();
  1293. }
  1294. break;
  1295. case NAMESPACE:
  1296. {
  1297. if (copyNamespaces)
  1298. {
  1299. OMNamespace ns = AxiomSupport.dynamicDowncastNamespace(node);
  1300. handler.namespace(ns.getPrefix(), ns.getNamespaceURI());
  1301. }
  1302. }
  1303. break;
  1304. case COMMENT:
  1305. {
  1306. OMComment comment = AxiomSupport.dynamicDowncastComment(node);
  1307. handler.comment(comment.getValue());
  1308. }
  1309. break;
  1310. case PROCESSING_INSTRUCTION:
  1311. {
  1312. OMProcessingInstruction pi = AxiomSupport.dynamicDowncastProcessingInstruction(node);
  1313. handler.processingInstruction(pi.getTarget(), pi.getValue());
  1314. }
  1315. break;
  1316. default:
  1317. {
  1318. throw new AssertionError(getNodeKind(node));
  1319. }
  1320. }
  1321. }
  1322. /**
  1323. * Determines whether the cancellation, xmlns="", is required to ensure correct semantics.
  1324. *
  1325. * @param element
  1326. * The element that would be the parent of the cancellation.
  1327. * @return <code>true</code> if the cancellation is required.
  1328. */
  1329. private static boolean isNamespaceCancellationRequired(final OMElement element)
  1330. {
  1331. final OMContainer parent = element.getParent();
  1332. if (null != parent)
  1333. {
  1334. final OMElement scope = AxiomSupport.dynamicDowncastElement(parent);
  1335. if (null != scope)
  1336. {
  1337. final OMNamespace scopeDefaultNS = scope.findNamespaceURI(XMLConstants.DEFAULT_NS_PREFIX);
  1338. if (null != scopeDefaultNS)
  1339. {
  1340. if (scopeDefaultNS.getNamespaceURI().length() > 0)
  1341. {
  1342. return true;
  1343. }
  1344. else
  1345. {
  1346. // The scope is the global namespace so the cancellation
  1347. // can be ignored.
  1348. }
  1349. }
  1350. else
  1351. {
  1352. // There does not seem to be any conflict so ignore the
  1353. // mapping.
  1354. }
  1355. }
  1356. else
  1357. {
  1358. // The parent must be a document, so the mapping must be
  1359. // spurious.
  1360. }
  1361. }
  1362. else
  1363. {
  1364. // If there is no parent then the mapping is ambiguous. Ignore it.
  1365. }
  1366. return false;
  1367. }
  1368. private static boolean isNamespaceDeclarationRequired(final String prefix, final String uri, final OMElement element)
  1369. {
  1370. final OMContainer parent = element.getParent();
  1371. if (null != parent)
  1372. {
  1373. OMElement scope = AxiomSupport.dynamicDowncastElement(parent);
  1374. while (null != scope)
  1375. {
  1376. final OMNamespace namespace = scope.findNamespaceURI(prefix);
  1377. if (null != namespace)
  1378. {
  1379. // The prefix is mapped to something in a higher scope.
  1380. if (!namespace.getNamespaceURI().equals(uri))
  1381. {
  1382. // The mapping must be overridden.
  1383. return true;
  1384. }
  1385. else
  1386. {
  1387. // The mapping already exists.
  1388. return false;
  1389. }
  1390. }
  1391. scope = AxiomSupport.dynamicDowncastElement(scope.getParent());
  1392. }
  1393. }
  1394. else
  1395. {
  1396. // If there is no parent then the mapping is required.
  1397. }
  1398. return true;
  1399. }
  1400. }