X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2Facr%2Fxml%2FDomContent.java;h=514d0bd36db23b505577db2bb4b2c13f62a75611;hb=1d6840195189cbdbf632ca2800b6179d3b6349df;hp=ac863403deed8138a298cb25a0efd5ce098c7d0a;hpb=dcdbf77c4ec46f1dcad5d3fa011fe072e921f187;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.cms/src/org/argeo/cms/acr/xml/DomContent.java b/org.argeo.cms/src/org/argeo/cms/acr/xml/DomContent.java index ac863403d..514d0bd36 100644 --- a/org.argeo.cms/src/org/argeo/cms/acr/xml/DomContent.java +++ b/org.argeo.cms/src/org/argeo/cms/acr/xml/DomContent.java @@ -1,8 +1,11 @@ package org.argeo.cms.acr.xml; import java.nio.CharBuffer; +import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; +import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -10,15 +13,23 @@ import java.util.concurrent.CompletableFuture; import javax.xml.XMLConstants; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; import org.argeo.api.acr.Content; import org.argeo.api.acr.ContentName; +import org.argeo.api.acr.CrName; import org.argeo.api.acr.spi.ProvidedContent; import org.argeo.api.acr.spi.ProvidedSession; import org.argeo.cms.acr.AbstractContent; import org.argeo.cms.acr.ContentUtils; import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -28,7 +39,6 @@ import org.w3c.dom.Text; /** Content persisted as a DOM element. */ public class DomContent extends AbstractContent implements ProvidedContent { - private final ProvidedSession session; private final DomContentProvider provider; private final Element element; @@ -36,7 +46,7 @@ public class DomContent extends AbstractContent implements ProvidedContent { private Boolean hasText = null; public DomContent(ProvidedSession session, DomContentProvider contentProvider, Element element) { - this.session = session; + super(session); this.provider = contentProvider; this.element = element; } @@ -47,16 +57,24 @@ public class DomContent extends AbstractContent implements ProvidedContent { @Override public QName getName() { - if (element.getParentNode() == null) {// root + if (isLocalRoot()) {// root String mountPath = provider.getMountPath(); if (mountPath != null) { - Content mountPoint = session.getMountPoint(mountPath); - return mountPoint.getName(); + if (ContentUtils.ROOT_SLASH.equals(mountPath)) { + return CrName.root.qName(); + } + Content mountPoint = getSession().getMountPoint(mountPath); + QName mountPointName = mountPoint.getName(); + return mountPointName; } } return toQName(this.element); } + protected boolean isLocalRoot() { + return element.getParentNode() == null || element.getParentNode() instanceof Document; + } + protected QName toQName(Node node) { String prefix = node.getPrefix(); if (prefix == null) { @@ -104,6 +122,8 @@ public class DomContent extends AbstractContent implements ProvidedContent { for (int i = 0; i < attributes.getLength(); i++) { Attr attr = (Attr) attributes.item(i); QName key = toQName(attr); + if (key.getNamespaceURI().equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) + continue;// skip prefix mapping result.add(key); } return result; @@ -121,7 +141,7 @@ public class DomContent extends AbstractContent implements ProvidedContent { else return Optional.empty(); } else - return null; + return Optional.empty(); } @Override @@ -198,21 +218,24 @@ public class DomContent extends AbstractContent implements ProvidedContent { @Override public Iterator iterator() { NodeList nodeList = element.getChildNodes(); - return new ElementIterator(this, session, provider, nodeList); + return new ElementIterator(this, getSession(), provider, nodeList); } @Override public Content getParent() { Node parentNode = element.getParentNode(); - if (parentNode == null) { + if (isLocalRoot()) { String mountPath = provider.getMountPath(); if (mountPath == null) return null; + if (ContentUtils.ROOT_SLASH.equals(mountPath)) { + return null; + } String[] parent = ContentUtils.getParentPath(mountPath); - return session.get(parent[0]); + if (ContentUtils.EMPTY.equals(parent[0])) + return null; + return getSession().get(parent[0]); } - if (parentNode instanceof Document) - return null; if (!(parentNode instanceof Element)) throw new IllegalStateException("Parent is not an element"); return new DomContent(this, (Element) parentNode); @@ -254,6 +277,9 @@ public class DomContent extends AbstractContent implements ProvidedContent { String textContent = element.getTextContent(); CharBuffer buf = CharBuffer.wrap(textContent); return (A) buf; + } else if (Source.class.isAssignableFrom(clss)) { + DOMSource source = new DOMSource(element); + return (A) source; } return super.adapt(clss); } @@ -263,14 +289,97 @@ public class DomContent extends AbstractContent implements ProvidedContent { if (String.class.isAssignableFrom(clss)) { CompletableFuture res = new CompletableFuture<>(); res.thenAccept((s) -> { - session.notifyModification(this); + getSession().notifyModification(this); element.setTextContent(s); }); return (CompletableFuture) res; + } else if (Source.class.isAssignableFrom(clss)) { + CompletableFuture res = new CompletableFuture<>(); + res.thenAccept((source) -> { + try { + Transformer transformer = provider.getTransformerFactory().newTransformer(); + DocumentFragment documentFragment = element.getOwnerDocument().createDocumentFragment(); + DOMResult result = new DOMResult(documentFragment); + transformer.transform(source, result); + // Node parentNode = element.getParentNode(); + Element resultElement = (Element) documentFragment.getFirstChild(); + QName resultName = toQName(resultElement); + if (!resultName.equals(getName())) + throw new IllegalArgumentException(resultName + "+ is not compatible with " + getName()); + + // attributes + NamedNodeMap attrs = resultElement.getAttributes(); + for (int i = 0; i < attrs.getLength(); i++) { + Attr attr2 = (Attr) element.getOwnerDocument().importNode(attrs.item(i), true); + element.getAttributes().setNamedItem(attr2); + } + + // Move all the children + while (element.hasChildNodes()) { + element.removeChild(element.getFirstChild()); + } + while (resultElement.hasChildNodes()) { + element.appendChild(resultElement.getFirstChild()); + } +// parentNode.replaceChild(resultNode, element); +// element = (Element)resultNode; + + } catch (DOMException | TransformerException e) { + throw new RuntimeException("Cannot write to element", e); + } + }); + return (CompletableFuture) res; } return super.write(clss); } + @Override + public int getSiblingIndex() { + Node curr = element.getPreviousSibling(); + int count = 1; + while (curr != null) { + if (curr instanceof Element) { + if (Objects.equals(curr.getNamespaceURI(), element.getNamespaceURI()) + && Objects.equals(curr.getLocalName(), element.getLocalName())) { + count++; + } + } + curr = curr.getPreviousSibling(); + } + return count; + } + + /* + * TYPING + */ + @Override + public List getContentClasses() { + List res = new ArrayList<>(); + if (isLocalRoot()) { + String mountPath = provider.getMountPath(); + if (mountPath != null) { + Content mountPoint = getSession().getMountPoint(mountPath); + res.addAll(mountPoint.getContentClasses()); + } + } else { + res.add(getName()); + } + return res; + } + + @Override + public void addContentClasses(QName... contentClass) { + if (isLocalRoot()) { + String mountPath = provider.getMountPath(); + if (mountPath != null) { + Content mountPoint = getSession().getMountPoint(mountPath); + mountPoint.addContentClasses(contentClass); + } + } else { + super.addContentClasses(contentClass); + } + } + /* * MOUNT MANAGEMENT */ @@ -282,10 +391,7 @@ public class DomContent extends AbstractContent implements ProvidedContent { return new DomContent(this, childElement); } - public ProvidedSession getSession() { - return session; - } - + @Override public DomContentProvider getProvider() { return provider; }