Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

completed jquery mixing template aka htmlcomposer, still full css

matching missing
  • Loading branch information...
commit ab0cfd2522c9f7fe82ea5cfa82f89cd52ef7c0ca 1 parent 020e86e
@michelegonella authored
View
18 zen-base/src/main/java/com/nominanuda/xml/SAXPipeline.java
@@ -92,6 +92,18 @@ public SAXPipeline complete() {
}
return this;
}
+
+ public SAXResult build(Result result) {
+ if(! completed) {
+ complete();
+ }
+ try {
+ return (SAXResult)buildInternal(result);
+ } catch (TransformerConfigurationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
public Runnable build(final Source source, final Result result) {
if(! completed) {
complete();
@@ -99,7 +111,7 @@ public Runnable build(final Source source, final Result result) {
return new Runnable() {
public void run() {
try {
- txFactory.newTransformer().transform(source, build(result));
+ txFactory.newTransformer().transform(source, buildInternal(result));
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -113,7 +125,7 @@ public Runnable build(final SAXEmitter emitter, final SAXResult result) {
return new Runnable() {
public void run() {
try {
- emitter.toSAX(((SAXResult)build(result)).getHandler());
+ emitter.toSAX(((SAXResult)buildInternal(result)).getHandler());
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -133,7 +145,7 @@ private TransformerHandler buildTranformerHandler(Object c) throws TransformerCo
}
}
- private Result build(final Result result) throws TransformerConfigurationException {
+ private Result buildInternal(final Result result) throws TransformerConfigurationException {
Check.illegalstate.assertTrue(completed);
Result nextRes = result;
Iterator<Object> itr = components.iterator();
View
247 zen-webservice/src/main/java/com/nominanuda/web/htmlcomposer/DomManipulationHandler.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2008-2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.nominanuda.web.htmlcomposer;
+
+import java.util.Stack;
+
+import javax.xml.transform.sax.SAXResult;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+import com.nominanuda.code.Nullable;
+import com.nominanuda.lang.Fun0;
+import com.nominanuda.lang.Strings;
+import com.nominanuda.lang.Tuple2;
+import com.nominanuda.xml.ForwardingTransformerHandlerBase;
+import com.nominanuda.xml.SwallowingTransformerHandlerBase;
+import com.nominanuda.xml.SaxBuffer.SaxBit;
+
+public abstract class DomManipulationHandler extends ForwardingTransformerHandlerBase {
+ private int nestingLevel = 0;
+ private final DomManipulationStmt stmt;
+ private Stack<Tuple2<Integer, Fun0<Void>>> triggerStack = new Stack<Tuple2<Integer,Fun0<Void>>>();
+ private ContentHandler liveContentHandler;
+ private final static ContentHandler devNull = new SwallowingTransformerHandlerBase();
+
+ public static DomManipulationHandler build(DomManipulationStmt stmt) {
+ switch (stmt.getOperation()) {
+ case html:
+ return new HtmlHandler(stmt);
+ case replaceWith:
+ return new ReplaceWithHandler(stmt);
+ case before:
+ return new BeforeHandler(stmt);
+ case after:
+ return new AfterHandler(stmt);
+ case prepend:
+ return new PrependHandler(stmt);
+ case append:
+ return new AppendHandler(stmt);
+ }
+ throw new IllegalStateException("unsupported operation:" + stmt.getOperation().name());
+ }
+
+ private DomManipulationHandler(DomManipulationStmt domManipulationStmt) {
+ stmt = domManipulationStmt;
+ }
+
+ protected String getSelector() {
+ return stmt.getSelector();
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName,
+ Attributes atts) throws SAXException {
+ nestingLevel++;
+ if(matches(localName, atts)) {
+ onMatchedStartElement(uri, localName, qName, atts);
+ } else {
+ super.startElement(uri, localName, qName, atts);
+ }
+ }
+
+ protected abstract void onMatchedStartElement(String uri, String localName, String qName,
+ Attributes atts) throws SAXException;
+
+ private void onTriggerEndElement() {
+ Fun0<Void> f = triggerStack.pop().get1();
+ f.apply();
+ }
+
+ protected void pushTriggerEndElement(Fun0<Void> trigger) {
+ triggerStack.push(new Tuple2<Integer, Fun0<Void>>(nestingLevel, trigger));
+ };
+
+ @Override
+ public void endElement(String uri, String localName, String qName)
+ throws SAXException {
+ if(! triggerStack.isEmpty() && triggerStack.peek().get0() == nestingLevel) {
+ onTriggerEndElement();
+ } else {
+ super.endElement(uri, localName, qName);
+ }
+ nestingLevel--;
+ }
+
+ //TODO
+ private boolean matches(String tag, Attributes atts) {
+ if(getSelector().startsWith(".")) {
+ if(classMatches(atts.getValue("class"), getSelector().substring(1))) {
+ return true;
+ }
+ } else if(true) {
+ if(tag.equals(getSelector())) {
+ return true;
+ }
+ }
+ return false;//TODO
+ }
+
+ private boolean classMatches(@Nullable String clsAttr, String targetClass) {
+ return clsAttr != null && Strings.splitAndTrim(clsAttr, "\\s+").contains(targetClass);
+ }
+
+ protected void turnOnOutput() {
+ if(liveContentHandler == null) {
+ liveContentHandler = getTarget();
+ }
+ setResult(new SAXResult(liveContentHandler));
+ }
+ protected void turnOffOutput() {
+ if(liveContentHandler == null) {
+ liveContentHandler = getTarget();
+ }
+ setResult(new SAXResult(devNull));
+ }
+ protected void streamFragment() throws SAXException {
+ ContentHandler ch = getTarget();
+ for(SaxBit b : stmt.getSaxBuffer().getBits()) {
+ b.send(ch);
+ }
+ }
+
+ private static class HtmlHandler extends DomManipulationHandler {
+ public HtmlHandler(DomManipulationStmt domManipulationStmt) {
+ super(domManipulationStmt);
+ }
+ @Override
+ protected void onMatchedStartElement(final String uri, final String localName,
+ final String qName, final Attributes atts) throws SAXException {
+ turnOffOutput();
+ pushTriggerEndElement(new Fun0<Void>() {
+ public Void apply() {
+ try {
+ turnOnOutput();
+ getTarget().startElement(uri, localName, qName, atts);
+ streamFragment();
+ getTarget().endElement(uri, localName, qName);
+ return null;
+ } catch (SAXException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ }
+ }
+ private static class ReplaceWithHandler extends DomManipulationHandler {
+ public ReplaceWithHandler(DomManipulationStmt domManipulationStmt) {
+ super(domManipulationStmt);
+ }
+ @Override
+ protected void onMatchedStartElement(final String uri, final String localName,
+ final String qName, final Attributes atts) throws SAXException {
+ turnOffOutput();
+ pushTriggerEndElement(new Fun0<Void>() {
+ public Void apply() {
+ try {
+ turnOnOutput();
+ streamFragment();
+ return null;
+ } catch (SAXException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ }
+ }
+ private static class BeforeHandler extends DomManipulationHandler {
+ public BeforeHandler(DomManipulationStmt domManipulationStmt) {
+ super(domManipulationStmt);
+ }
+ @Override
+ protected void onMatchedStartElement(final String uri, final String localName,
+ final String qName, final Attributes atts) throws SAXException {
+ streamFragment();
+ getTarget().startElement(uri, localName, qName, atts);
+ }
+ }
+ private static class PrependHandler extends DomManipulationHandler {
+ public PrependHandler(DomManipulationStmt domManipulationStmt) {
+ super(domManipulationStmt);
+ }
+ @Override
+ protected void onMatchedStartElement(final String uri, final String localName,
+ final String qName, final Attributes atts) throws SAXException {
+ getTarget().startElement(uri, localName, qName, atts);
+ streamFragment();
+ }
+ }
+ private static class AppendHandler extends DomManipulationHandler {
+ public AppendHandler(DomManipulationStmt domManipulationStmt) {
+ super(domManipulationStmt);
+ }
+ @Override
+ protected void onMatchedStartElement(final String uri, final String localName,
+ final String qName, final Attributes atts) throws SAXException {
+ getTarget().startElement(uri, localName, qName, atts);
+ pushTriggerEndElement(new Fun0<Void>() {
+ public Void apply() {
+ try {
+ streamFragment();
+ getTarget().endElement(uri, localName, qName);
+ return null;
+ } catch (SAXException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ }
+ }
+ private static class AfterHandler extends DomManipulationHandler {
+ public AfterHandler(DomManipulationStmt domManipulationStmt) {
+ super(domManipulationStmt);
+ }
+ @Override
+ protected void onMatchedStartElement(final String uri, final String localName,
+ final String qName, final Attributes atts) throws SAXException {
+ getTarget().startElement(uri, localName, qName, atts);
+ pushTriggerEndElement(new Fun0<Void>() {
+ public Void apply() {
+ try {
+ getTarget().endElement(uri, localName, qName);
+ streamFragment();
+ return null;
+ } catch (SAXException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ }
+ }
+
+}
View
8 zen-webservice/src/main/java/com/nominanuda/web/htmlcomposer/DomManipulationStmt.java
@@ -22,10 +22,10 @@
@Immutable
public class DomManipulationStmt {
- final String selector;
- final ObjectFactory<SaxBuffer> saxBufferFactory;
- final DomOp operation;
- SaxBuffer saxBuffer;
+ private final String selector;
+ private final ObjectFactory<SaxBuffer> saxBufferFactory;
+ private final DomOp operation;
+ private SaxBuffer saxBuffer;
public DomManipulationStmt(String selector, ObjectFactory<SaxBuffer> saxBufferFactory,
DomOp operation) {
View
48 zen-webservice/src/main/java/com/nominanuda/web/htmlcomposer/HtmlFragmentChecker.java
@@ -1,48 +0,0 @@
-/*
- * Copyright 2008-2011 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.nominanuda.web.htmlcomposer;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-
-import com.nominanuda.web.http.HttpProtocol;
-import com.nominanuda.xml.ForwardingTransformerHandlerBase;
-
-public class HtmlFragmentChecker extends ForwardingTransformerHandlerBase implements HttpProtocol {
-
- public void startDocument() throws SAXException {
- }
-
- public void endDocument() throws SAXException {
- }
-
- public void startElement(String uri, String localName, String qName,
- Attributes atts) throws SAXException {
- if(! HTMLNS.equals(uri)) {
- uri = HTMLNS;
- }
- super.startElement(uri, localName, qName, atts);
- }
-
- public void endElement(String uri, String localName, String qName)
- throws SAXException {
- if(! HTMLNS.equals(uri)) {
- uri = HTMLNS;
- }
- super.endElement(uri, localName, qName);
- }
-
-}
View
46 zen-webservice/src/main/java/com/nominanuda/web/htmlcomposer/HtmlSaxPage.java
@@ -16,35 +16,49 @@
package com.nominanuda.web.htmlcomposer;
import java.util.LinkedList;
+import java.util.List;
+
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.sax.TransformerHandler;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
+import com.nominanuda.lang.InstanceFactory;
+import com.nominanuda.web.http.HttpProtocol;
import com.nominanuda.xml.SAXEmitter;
+import com.nominanuda.xml.SAXPipeline;
import com.nominanuda.xml.SaxBuffer;
-import com.nominanuda.xml.SaxBuffer.SaxBit;
-
-//TODO replace html in split blocks
-public class HtmlSaxPage implements SAXEmitter {
- String htmlns = "http://www.w3.org/1999/xhtml";
- LinkedList<SaxBit> bits = new LinkedList<SaxBit>();
- public HtmlSaxPage() {
- bits.add(new SaxBuffer.StartElement(htmlns, "body", "body", new AttributesImpl()));
- bits.add(new SaxBuffer.EndElement(htmlns, "body", "body"));
- }
+public class HtmlSaxPage implements SAXEmitter, HttpProtocol {
+ private static final String BODY = "body";
+ private static final String HEAD = "head";
+ private final List<DomManipulationStmt> stmts = new LinkedList<DomManipulationStmt>();
public void applyStmt(DomManipulationStmt domManipulationStmt) {
- JQuerySaxMatcher m = new JQuerySaxMatcher(domManipulationStmt);
- for(int i = 0; i < bits.size();) {
- i = m.match(bits, i);
- }
+ stmts.add(domManipulationStmt);
}
public void toSAX(ContentHandler ch) throws SAXException {
- for(SaxBit b : bits) {
- b.send(ch);
+ ContentHandler x = buildPipe(ch);
+ new SaxBuffer.StartElement(HTMLNS, HEAD, HEAD, new AttributesImpl()).send(x);
+ new SaxBuffer.EndElement(HTMLNS, HEAD, HEAD).send(x);
+ new SaxBuffer.StartElement(HTMLNS, BODY, BODY, new AttributesImpl()).send(x);
+ new SaxBuffer.EndElement(HTMLNS, BODY, BODY).send(x);
+ }
+
+ private ContentHandler buildPipe(ContentHandler ch) {
+ SAXPipeline p = new SAXPipeline();
+ for(DomManipulationStmt stmt : stmts) {
+ TransformerHandler instance = buildHandler(stmt);
+ p.add(new InstanceFactory<TransformerHandler>(instance));
}
+ ContentHandler x = p.complete().build(new SAXResult(ch)).getHandler();
+ return x;
+ }
+
+ private TransformerHandler buildHandler(DomManipulationStmt stmt) {
+ return DomManipulationHandler.build(stmt);
}
}
View
95 zen-webservice/src/main/java/com/nominanuda/web/htmlcomposer/JQuerySaxMatcher.java
@@ -1,95 +0,0 @@
-/*
- * Copyright 2008-2011 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.nominanuda.web.htmlcomposer;
-
-import java.util.LinkedList;
-import java.util.List;
-
-import javax.xml.transform.sax.SAXResult;
-import javax.xml.transform.sax.TransformerHandler;
-
-import com.nominanuda.code.Nullable;
-import com.nominanuda.lang.InstanceFactory;
-import com.nominanuda.lang.Strings;
-import com.nominanuda.web.htmlcomposer.DomOp;
-import com.nominanuda.xml.SAXPipeline;
-import com.nominanuda.xml.SaxBuffer;
-import com.nominanuda.xml.SaxBuffer.SaxBit;
-import com.nominanuda.xml.SaxBuffer.StartElement;
-
-public class JQuerySaxMatcher {
- private final DomOp operation;
- private String selector;
- private SaxBuffer saxBuf;
-
- public JQuerySaxMatcher(DomManipulationStmt domManipulationStmt) {
- operation = domManipulationStmt.getOperation();
- selector = domManipulationStmt.getSelector();
- saxBuf = new SaxBuffer();
- new SAXPipeline()
- .add(new InstanceFactory<TransformerHandler>(new HtmlFragmentChecker()))
- .complete()
- .build(domManipulationStmt.getSaxBuffer(), new SAXResult(saxBuf))
- .run();
- }
-
- public int match(LinkedList<SaxBit> bits, int i) {
- SaxBit bit = bits.get(i);
- List<SaxBit> sbl = saxBuf.getBits();
- if(SaxBuffer.isStartElement(bit) && selector.startsWith(".") && operation == DomOp.prepend) {
- StartElement se = (StartElement)bit;
-// String cls = se.attrs.getValue("class");
- if(classMatches(se.attrs.getValue("class"), selector.substring(1))) {
- int added = 0;
- for(int j = sbl.size() - 1; j >= 0; j--) {
- SaxBit bb = clean(sbl.get(j));
- if(isRelevant(bb)) {
- bits.add(i+1, bb);
- added++;
- }
- }
- return i + added;
- }
- } else if(SaxBuffer.isStartElement(bit) && operation == DomOp.html) {
- StartElement se = (StartElement)bit;
- if(se.localName.equals(selector)) {
- int added = 0;
- for(int j = sbl.size() - 1; j >= 0; j--) {
- SaxBit bb = clean(sbl.get(j));
- if(isRelevant(bb)) {
- bits.add(i+1, bb);
- added++;
- }
- }
- return i + added;
- }
- }
- return i+1;
- }
-
- private boolean classMatches(@Nullable String clsAttr, String targetClass) {
- return clsAttr != null && Strings.splitAndTrim(clsAttr, "\\s+").contains(targetClass);
- }
-
- private SaxBit clean(SaxBit saxBit) {
- return saxBit;
- }
-
- private boolean isRelevant(SaxBit bb) {
-
- return ! (SaxBuffer.isStartDocument(bb)||SaxBuffer.isEndDocument(bb));
- }
-}
View
87 zen-webservice/src/test/java/com/nominanuda/web/htmlcomposer/HtmlSaxPageTest.java
@@ -0,0 +1,87 @@
+package com.nominanuda.web.htmlcomposer;
+
+import static com.nominanuda.web.htmlcomposer.DomOp.after;
+import static com.nominanuda.web.htmlcomposer.DomOp.append;
+import static com.nominanuda.web.htmlcomposer.DomOp.before;
+import static com.nominanuda.web.htmlcomposer.DomOp.html;
+import static com.nominanuda.web.htmlcomposer.DomOp.prepend;
+import static com.nominanuda.web.htmlcomposer.DomOp.replaceWith;
+import static org.junit.Assert.assertEquals;
+
+import java.io.CharArrayWriter;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.util.LinkedList;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.sax.SAXSource;
+
+import nu.validator.htmlparser.sax.HtmlParser;
+
+import org.apache.log4j.BasicConfigurator;
+import org.junit.Test;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+import com.nominanuda.io.ReaderInputStream;
+import com.nominanuda.lang.InstanceFactory;
+import com.nominanuda.lang.ObjectFactory;
+import com.nominanuda.web.http.HttpProtocol;
+import com.nominanuda.xml.HtmlFragmentParser;
+import com.nominanuda.xml.SAXPipeline;
+import com.nominanuda.xml.SaxBuffer;
+import com.nominanuda.xml.XHtml5Serializer;
+
+public class HtmlSaxPageTest implements HttpProtocol {
+ static {
+ BasicConfigurator.configure();
+ }
+ @Test
+ public void test() throws SAXException {
+ LinkedList<DomManipulationStmt> stmts = new LinkedList<DomManipulationStmt>();
+ stmts.add(new DomManipulationStmt("body", f("<div/>"), html));
+ stmts.add(new DomManipulationStmt("div", f("abc"), html));
+ stmts.add(new DomManipulationStmt("div", f("0<p>1</p>1.5<p>2</p>3"), replaceWith));
+ stmts.add(new DomManipulationStmt("p", f("BEFOREP"), before));
+ stmts.add(new DomManipulationStmt("p", f("AFTERP"), after));
+ stmts.add(new DomManipulationStmt("p", f("PREPENDP"), prepend));
+ stmts.add(new DomManipulationStmt("p", f("APPENDP"), append));
+ streamPage(stmts);
+ }
+
+ private void streamPage(Iterable<DomManipulationStmt> stmts)
+ throws SAXException {
+ HtmlSaxPage p = new HtmlSaxPage();
+ for(DomManipulationStmt stmt : stmts) {
+ p.applyStmt(stmt);
+ }
+ CharArrayWriter out = new CharArrayWriter();
+ XHtml5Serializer ser = new XHtml5Serializer(out);
+ new SaxBuffer.StartDocument().send(ser);
+ new SaxBuffer.StartElement(HTMLNS,"html","html",new AttributesImpl()).send(ser);
+ p.toSAX(ser);
+ new SaxBuffer.EndElement(HTMLNS,"html","html").send(ser);
+ new SaxBuffer.EndDocument().send(ser);
+ assertEquals("<html><head></head><body>0BEFOREP<p>PREPENDP1APPENDP</p>AFTERP1.5BEFOREP<p>PREPENDP2APPENDP</p>AFTERP3</body></html>", out.toString());
+ }
+
+ private ObjectFactory<SaxBuffer> f(String s) {
+ InputStream is = new ReaderInputStream(new StringReader(s), UTF_8);
+ SaxBuffer sbuf = new SaxBuffer();
+ new SAXPipeline()
+ .complete()
+ .build(saxSource(is), new SAXResult(sbuf))
+ .run();
+ return new InstanceFactory<SaxBuffer>(sbuf);
+ }
+
+ private Source saxSource(InputStream is) {
+ HtmlParser parser = new HtmlParser();
+ parser.setMappingLangToXmlLang(true);
+ parser.setReportingDoctype(false);
+ SAXSource src = new SAXSource(new HtmlFragmentParser(parser), new InputSource(is));
+ return src;
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.