1 package org
.argeo
.cms
.acr
.xml
;
3 import java
.util
.HashSet
;
4 import java
.util
.Iterator
;
5 import java
.util
.Optional
;
8 import javax
.xml
.XMLConstants
;
9 import javax
.xml
.namespace
.NamespaceContext
;
10 import javax
.xml
.namespace
.QName
;
12 import org
.argeo
.api
.acr
.Content
;
13 import org
.argeo
.api
.acr
.ContentName
;
14 import org
.argeo
.api
.acr
.spi
.AbstractContent
;
15 import org
.argeo
.api
.acr
.spi
.ProvidedContent
;
16 import org
.argeo
.api
.acr
.spi
.ProvidedSession
;
17 import org
.w3c
.dom
.Attr
;
18 import org
.w3c
.dom
.Document
;
19 import org
.w3c
.dom
.Element
;
20 import org
.w3c
.dom
.NamedNodeMap
;
21 import org
.w3c
.dom
.Node
;
22 import org
.w3c
.dom
.NodeList
;
23 import org
.w3c
.dom
.Text
;
25 public class DomContent
extends AbstractContent
implements ProvidedContent
{
27 private final ProvidedSession session
;
28 private final DomContentProvider provider
;
29 private final Element element
;
31 // private String text = null;
32 private Boolean hasText
= null;
34 public DomContent(ProvidedSession session
, DomContentProvider contentProvider
, Element element
) {
35 this.session
= session
;
36 this.provider
= contentProvider
;
37 this.element
= element
;
40 public DomContent(DomContent context
, Element element
) {
41 this(context
.getSession(), context
.getProvider(), element
);
45 public QName
getName() {
46 return toQName(this.element
);
49 protected QName
toQName(Node node
) {
50 String prefix
= node
.getPrefix();
52 String namespaceURI
= node
.getNamespaceURI();
53 if (namespaceURI
== null)
54 namespaceURI
= node
.getOwnerDocument().lookupNamespaceURI(null);
55 if (namespaceURI
== null) {
56 return toQName(node
, node
.getLocalName());
58 String contextPrefix
= provider
.getPrefix(namespaceURI
);
59 if (contextPrefix
== null)
60 throw new IllegalStateException("Namespace " + namespaceURI
+ " is unbound");
61 return toQName(node
, namespaceURI
, node
.getLocalName(), provider
);
64 String namespaceURI
= node
.getNamespaceURI();
65 if (namespaceURI
== null)
66 namespaceURI
= node
.getOwnerDocument().lookupNamespaceURI(prefix
);
67 if (namespaceURI
== null) {
68 namespaceURI
= provider
.getNamespaceURI(prefix
);
69 if (XMLConstants
.NULL_NS_URI
.equals(namespaceURI
))
70 throw new IllegalStateException("Prefix " + prefix
+ " is unbound");
71 // TODO bind the prefix in the document?
73 return toQName(node
, namespaceURI
, node
.getLocalName(), provider
);
77 protected QName
toQName(Node source
, String namespaceURI
, String localName
, NamespaceContext namespaceContext
) {
78 return new ContentName(namespaceURI
, localName
, namespaceContext
);
81 protected QName
toQName(Node source
, String localName
) {
82 return new ContentName(localName
);
85 * ATTRIBUTES OPERATIONS
89 public Iterable
<QName
> keys() {
90 // TODO implement an iterator?
91 Set
<QName
> result
= new HashSet
<>();
92 NamedNodeMap attributes
= element
.getAttributes();
93 for (int i
= 0; i
< attributes
.getLength(); i
++) {
94 Attr attr
= (Attr
) attributes
.item(i
);
95 QName key
= toQName(attr
);
101 @SuppressWarnings("unchecked")
103 public <A
> Optional
<A
> get(QName key
, Class
<A
> clss
) {
104 String namespaceUriOrNull
= XMLConstants
.NULL_NS_URI
.equals(key
.getNamespaceURI()) ?
null
105 : key
.getNamespaceURI();
106 if (element
.hasAttributeNS(namespaceUriOrNull
, key
.getLocalPart())) {
107 String value
= element
.getAttributeNS(namespaceUriOrNull
, key
.getLocalPart());
108 if (clss
.isAssignableFrom(String
.class))
109 return Optional
.of((A
) value
);
111 return Optional
.empty();
117 public Object
put(QName key
, Object value
) {
118 Object previous
= get(key
);
119 String namespaceUriOrNull
= XMLConstants
.NULL_NS_URI
.equals(key
.getNamespaceURI()) ?
null
120 : key
.getNamespaceURI();
121 element
.setAttributeNS(namespaceUriOrNull
,
122 namespaceUriOrNull
== null ? key
.getLocalPart() : key
.getPrefix() + ":" + key
.getLocalPart(),
128 public boolean hasText() {
129 // return element instanceof Text;
132 NodeList nodeList
= element
.getChildNodes();
133 if (nodeList
.getLength() > 1) {
137 nodes
: for (int i
= 0; i
< nodeList
.getLength(); i
++) {
138 Node node
= nodeList
.item(i
);
139 if (node
instanceof Text
) {
140 Text text
= (Text
) node
;
141 if (!text
.isElementContentWhitespace()) {
152 // text = element.getTextContent();
153 // return text != null;
157 public String
getText() {
159 return element
.getTextContent();
169 public Iterator
<Content
> iterator() {
170 NodeList nodeList
= element
.getChildNodes();
171 return new ElementIterator(this, session
, provider
, nodeList
);
175 public Content
getParent() {
176 Node parent
= element
.getParentNode();
179 if (parent
instanceof Document
)
181 if (!(parent
instanceof Element
))
182 throw new IllegalStateException("Parent is not an element");
183 return new DomContent(this, (Element
) parent
);
187 public Content
add(QName name
, QName
... classes
) {
188 // TODO consider classes
189 Document document
= this.element
.getOwnerDocument();
190 String namespaceUriOrNull
= XMLConstants
.NULL_NS_URI
.equals(name
.getNamespaceURI()) ?
null
191 : name
.getNamespaceURI();
192 Element child
= document
.createElementNS(namespaceUriOrNull
,
193 namespaceUriOrNull
== null ? name
.getLocalPart() : name
.getPrefix() + ":" + name
.getLocalPart());
194 element
.appendChild(child
);
195 return new DomContent(this, child
);
199 public void remove() {
200 // TODO make it more robust
201 element
.getParentNode().removeChild(element
);
206 protected void removeAttr(QName key
) {
207 String namespaceUriOrNull
= XMLConstants
.NULL_NS_URI
.equals(key
.getNamespaceURI()) ?
null
208 : key
.getNamespaceURI();
209 element
.removeAttributeNS(namespaceUriOrNull
,
210 namespaceUriOrNull
== null ? key
.getLocalPart() : key
.getPrefix() + ":" + key
.getLocalPart());
214 public ProvidedSession
getSession() {
218 public DomContentProvider
getProvider() {