Jelajahi Sumber

new: xml: document fragments
new: xml: XMLElement#content(String xml)
new: xml: XMLElement#content(XMLElement element)
new: xml: XMLElement#clear

Ranides Atterwim 10 tahun lalu
induk
melakukan
72e94a5247

+ 2 - 0
assira/src/main/java/net/ranides/assira/xml/XMLDocument.java

@@ -26,6 +26,8 @@ public interface XMLDocument {
     
     XMLElement fragment();
     
+    XMLElement fragment(String xml);
+    
     XMLElement tag(String tag);
     
     XMLElement tag(String ns, String tag);

+ 5 - 1
assira/src/main/java/net/ranides/assira/xml/XMLElement.java

@@ -89,9 +89,11 @@ public interface XMLElement extends Wrapper<String> {
     XMLElements siblings(Predicate<XMLContext> selector);
     
     
-    
+
     XMLElement normalize();
     
+    XMLElement clear();
+    
     XMLElement before(XMLElement element);
     
     XMLElement after(XMLElement element);
@@ -110,6 +112,8 @@ public interface XMLElement extends Wrapper<String> {
     
     XMLElement unwrap();
     
+    XMLElement content(XMLElement value);
+    
     XMLElement content(String value);
     
     XMLElement text(String value);

+ 4 - 0
assira/src/main/java/net/ranides/assira/xml/XMLElements.java

@@ -140,6 +140,8 @@ public interface XMLElements extends Iterable<XMLElement> {
 
     XMLElements normalize();
     
+    XMLElements clear();
+        
     XMLElements before(XMLElement element);
     
     XMLElements after(XMLElement element);
@@ -158,6 +160,8 @@ public interface XMLElements extends Iterable<XMLElement> {
     
     XMLElements unwrap();
     
+    XMLElements content(XMLElement value);
+    
     XMLElements content(String value);
     
     XMLElements text(String value);

+ 9 - 31
assira/src/main/java/net/ranides/assira/xml/XMLQuery.java

@@ -8,22 +8,15 @@
 package net.ranides.assira.xml;
 
 import java.io.File;
-import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
 import java.io.StringReader;
 import java.net.URI;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
 import net.ranides.assira.collection.query.CQueryBuilder;
-import net.ranides.assira.functional.CheckedSupplier;
-import net.ranides.assira.trace.ExceptionUtils;
 import net.ranides.assira.xml.impl.CElements;
+import net.ranides.assira.xml.impl.W3CQuery;
 import net.ranides.assira.xml.impl.W3Element;
 import org.w3c.dom.Node;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
 
 /**
  *
@@ -45,46 +38,31 @@ public final class XMLQuery {
     }
     
     public static XMLElement $(String doc) {
-        return $(new StringReader(doc));
+        return W3CQuery.$(new StringReader(doc));
     }
     
     public static XMLElement $(File doc) {
-        return $(() -> W3Element.wrap(builder().parse(doc)));
+        return W3CQuery.$(doc);
     }
     
     public static XMLElement $(URI doc) {
-        return $(() -> W3Element.wrap(builder().parse(doc.toString())));
+        return W3CQuery.$(doc);
     }
     
     public static XMLElement $(Reader doc) {
-        return $(() -> W3Element.wrap(builder().parse(new InputSource(doc))));
+        return W3CQuery.$(doc);
     }
     
     public static XMLElement $(InputStream doc) {
-        return $(() -> W3Element.wrap(builder().parse(new InputSource(doc))));
-    }
-    
-    private static XMLElement $(CheckedSupplier<XMLElement> supplier) {
-        try {
-            return supplier.get();
-        } catch (SAXException | ParserConfigurationException | IOException cause) {
-            throw new XMLException(cause);
-        } catch(Exception cause) {
-            throw ExceptionUtils.rethrow(cause);
-        }
+        return W3CQuery.$(doc);
     }
     
     public static XMLElements $(XMLElements... elements) {
-        return new CElements(CQueryBuilder.fromArray(elements).unfold(e -> e.stream()));
+        return W3CQuery.$(elements);
     }
     
     public static XMLElements $(XMLElement... elements) {
-        return new CElements(CQueryBuilder.fromArray(elements));
-    }
-    
-    private static DocumentBuilder builder() throws ParserConfigurationException {
-        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-        factory.setNamespaceAware(true);
-        return factory.newDocumentBuilder();
+        return W3CQuery.$(elements);
     }
+
 }

+ 10 - 0
assira/src/main/java/net/ranides/assira/xml/impl/CElements.java

@@ -338,6 +338,16 @@ public class CElements implements XMLElements {
         return each(n -> n.normalize());
     }
     
+    @Override
+    public XMLElements clear() {
+        return each(n -> n.clear());
+    }
+    
+    @Override
+    public XMLElements content(XMLElement value) {
+        return each(n -> n.content(value));
+    }
+    
     @Override
     public XMLElements content(String value) {
         return each(n -> n.content(value));

+ 110 - 0
assira/src/main/java/net/ranides/assira/xml/impl/W3CQuery.java

@@ -0,0 +1,110 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+
+package net.ranides.assira.xml.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.net.URI;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import net.ranides.assira.collection.query.CQueryBuilder;
+import net.ranides.assira.functional.CheckedSupplier;
+import net.ranides.assira.trace.ExceptionUtils;
+import net.ranides.assira.xml.XMLElement;
+import net.ranides.assira.xml.XMLElements;
+import net.ranides.assira.xml.XMLException;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+@SuppressWarnings("PMD.MethodNameRules")
+public final class W3CQuery {
+
+    private W3CQuery() {
+        /* utility class */
+    }
+    
+    public static XMLElement $(File doc) {
+        return $(() -> W3Element.wrap(builder().parse(doc)));
+    }
+    
+    public static XMLElement $(URI doc) {
+        return $(() -> W3Element.wrap(builder().parse(doc.toString())));
+    }
+    
+    public static XMLElement $(Reader doc) {
+        return $(() -> W3Element.wrap(builder().parse(new InputSource(doc))));
+    }
+    
+    public static XMLElement $(InputStream doc) {
+        return $(() -> W3Element.wrap(builder().parse(new InputSource(doc))));
+    }
+    
+    private static XMLElement $(CheckedSupplier<XMLElement> supplier) {
+        try {
+            return supplier.get();
+        } catch (SAXException | ParserConfigurationException | IOException cause) {
+            throw new XMLException(cause);
+        } catch(Exception cause) {
+            throw ExceptionUtils.rethrow(cause);
+        }
+    }
+    
+    public static XMLElements $(XMLElements... elements) {
+        return new CElements(CQueryBuilder.fromArray(elements).unfold(e -> e.stream()));
+    }
+    
+    public static XMLElements $(XMLElement... elements) {
+        return new CElements(CQueryBuilder.fromArray(elements));
+    }
+    
+    static XMLElement append(XMLElement target, String xml) {
+        Node content = parse(target, xml);
+        Node ntarget = target.node();
+        while (content.hasChildNodes()) {
+            ntarget.appendChild(content.removeChild(content.getFirstChild()));
+        }
+        return target;
+    }
+    
+    static XMLElement prepend(XMLElement target, String xml) {
+        Node content = parse(target, xml);
+        Node ntarget = target.node();
+        while (content.hasChildNodes()) {
+            ntarget.insertBefore(content.removeChild(content.getLastChild()), ntarget.getFirstChild());
+        }
+        return target;
+    }
+
+    private static Node parse(XMLElement target, String xml) {
+        try {
+            String wxml="<__fragment__>" + xml + "</__fragment__>";
+            Document cdoc = builder().parse(new InputSource(new StringReader(wxml)));
+            return target.document().node().importNode(cdoc.getDocumentElement(),true);
+        } catch(DOMException | IOException | ParserConfigurationException | SAXException cause) {
+            throw ExceptionUtils.rethrow(cause);
+        }
+    }
+    
+    private static DocumentBuilder builder() throws ParserConfigurationException {
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        factory.setNamespaceAware(true);
+        return factory.newDocumentBuilder();
+    }
+    
+}

+ 11 - 0
assira/src/main/java/net/ranides/assira/xml/impl/W3Document.java

@@ -6,10 +6,16 @@
  */
 package net.ranides.assira.xml.impl;
 
+import java.io.IOException;
+import javax.xml.parsers.DocumentBuilderFactory;
 import net.ranides.assira.generic.CompareUtils;
+import net.ranides.assira.trace.ExceptionUtils;
 import net.ranides.assira.xml.XMLDocument;
 import net.ranides.assira.xml.XMLElement;
+import net.ranides.assira.xml.XMLQuery;
 import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Node;
 
 /**
  *
@@ -53,6 +59,11 @@ public class W3Document implements XMLDocument {
         return new W3Element(doc.createDocumentFragment());
     }
     
+    @Override
+    public XMLElement fragment(String xml) {
+        return W3CQuery.append(fragment(), xml);
+    }
+    
     @Override
     public XMLElement tag(String tag) {
         return new W3Element(doc.createElement(tag));

+ 28 - 1
assira/src/main/java/net/ranides/assira/xml/impl/W3Element.java

@@ -330,9 +330,27 @@ public class W3Element extends CElement implements XMLElement {
 
     @Override
     public XMLElement content(String value) {
-        node.setNodeValue(value);
+        if(null != node.getNodeValue()) {
+            node.setNodeValue(value);
+        } else {
+            clear();
+            W3CQuery.append(this, value);
+        }
+        return this;
+    }
+
+    @Override
+    public XMLElement content(XMLElement value) {
+        if(null != node.getNodeValue()) {
+            node.setNodeValue(value.content());
+        } else {
+            clear();
+            append(value);
+        }
         return this;
     }
+    
+    
 
     @Override
     public XMLElement text(String value) {
@@ -340,6 +358,15 @@ public class W3Element extends CElement implements XMLElement {
         return this;
     }
 
+    @Override
+    public XMLElement clear() {
+        while(node.hasChildNodes()) {
+            node.removeChild(node.getFirstChild());
+        }
+        return this;
+    }
+
+    
     
     @Override
     public XMLElement normalize() {

+ 2 - 0
assira/src/test/java/net/ranides/assira/TestFiles.java

@@ -34,6 +34,8 @@ public final class TestFiles {
     
     public static final File XML_ELEMENTS = new File("src/test/resources/xml/elements.xml");
     
+    public static final File XML_CONTENT = new File("src/test/resources/xml/content.xml");
+    
     public static final File XSL_USERS = new File("src/test/resources/xml/users.xslt");
     
     public static final File XML_USERS = new File("src/test/resources/xml/users.xml");

+ 19 - 10
assira/src/test/java/net/ranides/assira/xml/impl/CElementsTest.java

@@ -293,16 +293,7 @@ public class CElementsTest {
         assertEquals(exp4, doc.find("user mail").parent("users").names());
         assertEquals(exp5, doc.find("user mail").parent(n -> true).names());
     }
-    
-    // @todo (assira #3.1) xml: DocumentFragment
-    // na ten moment nie ma sensownego sposobu, aby wkleić do dokumentu kawałek XMLa
-    // czyli coś w stylu: element.append("<h1>fff</h1><p>text</p>...")
-    // nie wiemy nawet do czego służy DocumentFrargment z w3c dom
-    //  - nasza funkcja XMLQuery.$(text) tworzy nowy dokument
-    //  - nie mamy żadnej funkcji, która dla bieżącego dokumentu dokleja część
-    //  - czy można w ogóle traktować fragment jako XMLElement ?
-    //  - może to musi być traktowane jako XMLElements ?
-    
+
     @Test
     public void testModification() throws IOException {
         XMLElement doc = $(TestFiles.XML_INPUT).normalize();
@@ -338,6 +329,24 @@ public class CElementsTest {
         String out = new XMLWriter().indent(4).toString(doc);
 //        System.out.printf("%s%n", out);
         assertEquals(IOStrings.read(TestFiles.XML_ELEMENTS, Charsets.UTF8), out);
+        
+        XMLElement e = builder.fragment()
+            .append(builder.tag("item1").text("value1"))
+            .append(builder.tag("item2").text("value2"))
+            .append(builder.tag("item2").text("<h1>value3</h1>"));
+        doc.find("configuration").append(e);
+        doc.find("configuration").append(e);
+        
+        XMLElement ddoc2 = builder.fragment("<var1>tt</var1><var2>tt</var2>");
+        
+        doc.find("configuration").append(ddoc2);
+        
+        doc.find("configuration var2").content("<ul class='list'><li>a</li><li>b</li></ul>");
+        String out2 = new XMLWriter().indent(4).toString(doc);
+        
+        System.out.printf("%s%n", out2);
+        assertEquals(IOStrings.read(TestFiles.XML_CONTENT, Charsets.UTF8), out2);
+        
     }
     
     private void debug(String format, List<String> list) {

+ 92 - 0
assira/src/test/resources/xml/content.xml

@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?info host='ccms.ranides.net'?><?info version='2.1'?><?params name='logger' level='2' out='file' ?><!-- @author Ranides Atterwim <ranides@gmail.com> --><ccms>
+    <users>
+        <!--active user-->
+        <meta>user:active</meta>
+        <user active="true" id="." public="true" uid="5461">
+            <login>!ranides</login>
+            <username>Ranides Atterwim</username>
+            <info>
+                <nomail>HIDDEN</nomail>
+            </info>
+            <!--no email information-->
+            <info>
+                <nomail>HIDDEN</nomail>
+            </info>
+            <!--no email information-->
+        </user>
+        <meta-v2>7</meta-v2>
+        <EOF/>
+        <!--active user-->
+        <meta>user:active</meta>
+        <user active="true" id="." uid="8721">
+            <login>!admin</login>
+            <username>undefined</username>
+            <info>
+                <nomail>HIDDEN</nomail>
+            </info>
+            <!--no email information-->
+        </user>
+        <meta-v2>7</meta-v2>
+        <EOF/>
+        <user active="false" id="." uid="7542">
+            <login>guest?</login>
+            <username>undefined</username>
+        </user>
+        <user active="false" id="." uid="1952">
+            <login>owner?</login>
+            <username>Tom</username>
+            <info>
+                <nomail>HIDDEN</nomail>
+            </info>
+            <!--no email information-->
+            <info>
+                <nomail>HIDDEN</nomail>
+            </info>
+            <!--no email information-->
+            <info>
+                <nomail>HIDDEN</nomail>
+            </info>
+            <!--no email information-->
+        </user>
+        <!--active user-->
+        <meta>user:active</meta>
+        <user active="true" id="." public="true" uid="3773">
+            <login>!saren</login>
+            <username>Sarenka</username>
+            <info>
+                <nomail>HIDDEN</nomail>
+            </info>
+            <!--no email information-->
+        </user>
+        <meta-v2>7</meta-v2>
+        <EOF/>
+    </users>
+    <data>
+        <item id="2015-01-35" text=""/>
+        <item id="2015-01-36" text=""/>
+        <item id="2015-01-41" text=""/>
+        <item id="2015-01-42" text=""/>
+        <item id="2015-01-56" text=""/>
+        <item id="2015-01-56" text=""/>
+        <item id="2015-01-56" text=""/>
+    </data>
+    <param name="2"/>
+    <configuration>
+        <param name="1"/>
+        <param name="3"/>
+        <item1>value1</item1>
+        <item2>value2</item2>
+        <item2>&lt;h1&gt;value3&lt;/h1&gt;</item2>
+        <item1>value1</item1>
+        <item2>value2</item2>
+        <item2>&lt;h1&gt;value3&lt;/h1&gt;</item2>
+        <var1>tt</var1>
+        <var2>
+            <ul class="list">
+                <li>a</li>
+                <li>b</li>
+            </ul>
+        </var2>
+    </configuration>
+</ccms>