Skip to content

Commit

Permalink
added toPrettyString(indent) method to sitemap generators
Browse files Browse the repository at this point in the history
  • Loading branch information
[email protected] authored and [email protected] committed Nov 9, 2019
1 parent 8801cb5 commit f8c41ad
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 19 deletions.
102 changes: 85 additions & 17 deletions src/main/java/cz/jiripinkas/jsitemapgenerator/AbstractGenerator.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
package cz.jiripinkas.jsitemapgenerator;

import cz.jiripinkas.jsitemapgenerator.exception.InvalidUrlException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Map;
import java.util.TreeMap;
Expand All @@ -12,9 +29,10 @@

/**
* Abstract Generator
*
* @param <I> Concrete implementation of AbstractGenerator, for example SitemapGenerator
*/
public abstract class AbstractGenerator <I extends AbstractGenerator> {
public abstract class AbstractGenerator<I extends AbstractGenerator> {

protected Map<String, WebPage> urls = new TreeMap<>();

Expand Down Expand Up @@ -75,6 +93,7 @@ public I addPage(String name) {

/**
* Add single page to sitemap.
*
* @param supplier Supplier method which sneaks any checked exception
* https://www.baeldung.com/java-sneaky-throws
* Allows for calling method which performs some operation and then returns name of page.
Expand All @@ -93,6 +112,7 @@ public I addPage(StringSupplierWithException<String> supplier) {
/**
* This method is called before adding a page to urls.
* It can be used to change webPage attributes
*
* @param webPage WebPage
*/
protected void beforeAddPageEvent(WebPage webPage) {
Expand Down Expand Up @@ -128,9 +148,9 @@ public I addPages(Supplier<Collection<WebPage>> webPagesSupplier) {
/**
* Add collection of pages to sitemap
*
* @param <T> This is the type parameter
* @param <T> This is the type parameter
* @param webPages Collection of pages
* @param mapper Mapper function which transforms some object to WebPage
* @param mapper Mapper function which transforms some object to WebPage
* @return this
*/
public <T> I addPages(Collection<T> webPages, Function<T, WebPage> mapper) {
Expand All @@ -143,9 +163,9 @@ public <T> I addPages(Collection<T> webPages, Function<T, WebPage> mapper) {
/**
* Add collection of pages to sitemap
*
* @param <T> This is the type parameter
* @param <T> This is the type parameter
* @param webPages Collection of pages
* @param mapper Mapper function which transforms some object to String. This will be passed to WebPage.of(name)
* @param mapper Mapper function which transforms some object to String. This will be passed to WebPage.of(name)
* @return this
*/
public <T> I addPageNames(Collection<T> webPages, Function<T, String> mapper) {
Expand All @@ -158,9 +178,9 @@ public <T> I addPageNames(Collection<T> webPages, Function<T, String> mapper) {
/**
* Add collection of pages to sitemap
*
* @param <T> This is the type parameter
* @param <T> This is the type parameter
* @param webPagesSupplier Collection of pages supplier
* @param mapper Mapper function which transforms some object to WebPage
* @param mapper Mapper function which transforms some object to WebPage
* @return this
*/
public <T> I addPages(Supplier<Collection<T>> webPagesSupplier, Function<T, WebPage> mapper) {
Expand All @@ -173,9 +193,9 @@ public <T> I addPages(Supplier<Collection<T>> webPagesSupplier, Function<T, WebP
/**
* Add collection of pages to sitemap
*
* @param <T> This is the type parameter
* @param <T> This is the type parameter
* @param webPagesSupplier Collection of pages supplier
* @param mapper Mapper function which transforms some object to String. This will be passed to WebPage.of(name)
* @param mapper Mapper function which transforms some object to String. This will be passed to WebPage.of(name)
* @return this
*/
public <T> I addPageNames(Supplier<Collection<T>> webPagesSupplier, Function<T, String> mapper) {
Expand All @@ -187,13 +207,14 @@ public <T> I addPageNames(Supplier<Collection<T>> webPagesSupplier, Function<T,

/**
* Run some method
*
* @param runnable Runnable method which sneaks any checked exception
* https://www.baeldung.com/java-sneaky-throws
* Usage:
* SitemapIndexGenerator.of(homepage)
* .run(() -&gt; methodToCall())
* .addPage(WebPage.of("test))
* .toString()
* .run(() -&gt; methodToCall())
* .addPage(WebPage.of("test))
* .toString()
* @return this
*/
public I run(RunnableWithException runnable) {
Expand All @@ -208,13 +229,14 @@ public I run(RunnableWithException runnable) {
/**
* Run some method. Argument is current generator,
* which allows to access current generator in run() method.
*
* @param consumer Consumer method which sneaks any checked exception
* https://www.baeldung.com/java-sneaky-throws
* Usage:
* SitemapIndexGenerator.of(homepage)
* .run(currentGenerator -&gt; { ... })
* .addPage(WebPage.of("test))
* .toString()
* .run(currentGenerator -&gt; { ... })
* .addPage(WebPage.of("test))
* .toString()
* @return this
*/
public I run(GeneratorConsumerWithException<I> consumer) {
Expand All @@ -229,7 +251,7 @@ public I run(GeneratorConsumerWithException<I> consumer) {

@SuppressWarnings("unchecked")
protected I getThis() {
return (I)this;
return (I) this;
}

public interface RunnableWithException {
Expand All @@ -246,7 +268,8 @@ public interface StringSupplierWithException<S> {

/**
* Sneak exception https://www.baeldung.com/java-sneaky-throws
* @param e Exception
*
* @param e Exception
* @param <E> Type parameter
* @throws E Sneaked exception
*/
Expand All @@ -255,4 +278,49 @@ private static <E extends Throwable> void sneakyThrow(Throwable e) throws E {
throw (E) e;
}

/**
* Method to prettify XML string
* @param xml Input XML
* @param indent Ident
* @return Prettified XML
*/
protected String toPrettyXmlString(String xml, int indent) {
try {
// Turn xml string into a document
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
Document document = documentBuilderFactory
.newDocumentBuilder()
.parse(new InputSource(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))));

// Remove whitespaces outside tags
document.normalize();
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList nodeList = (NodeList) xPath.evaluate("//text()[normalize-space()='']",
document,
XPathConstants.NODESET);

for (int i = 0; i < nodeList.getLength(); ++i) {
Node node = nodeList.item(i);
node.getParentNode().removeChild(node);
}

// Setup pretty print options
TransformerFactory transformerFactory = TransformerFactory.newInstance();
transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
transformerFactory.setAttribute("indent-number", indent);
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");

// Return pretty print xml string
StringWriter stringWriter = new StringWriter();
transformer.transform(new DOMSource(document), new StreamResult(stringWriter));
return stringWriter.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ public String toString() {
return result.toString();
}

/**
* Construct sitemap into single prettified String
* @param indent
* @return
*/
public String toPrettyString(int indent) {
return toPrettyXmlString(toString(), indent).replace("\r\n", "\n");
}

private ByteArrayOutputStream gzipIt(InputStream inputStream) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import org.junit.Before;
import org.junit.Test;

import java.time.LocalDateTime;

import static org.junit.Assert.*;

public class AbstractSitemapGeneratorTest {
Expand All @@ -13,8 +15,24 @@ public class AbstractSitemapGeneratorTest {
@Before
public void setUp() {
sitemapIndexGenerator = SitemapIndexGenerator.of("http://javalibs.com");
sitemapIndexGenerator.addPage(WebPage.builder().name("sitemap-plugins.xml").lastModNow().build());
sitemapIndexGenerator.addPage(WebPage.builder().name("sitemap-archetypes.xml").lastModNow().build());
sitemapIndexGenerator.addPage(WebPage.builder().name("sitemap-plugins.xml").lastMod(LocalDateTime.of(2018, 1, 1, 0, 0)).build());
sitemapIndexGenerator.addPage(WebPage.builder().name("sitemap-archetypes.xml").lastMod(LocalDateTime.of(2018, 1, 1, 0, 0)).build());
}

@Test
public void toPrettyString() {
String actualSitemapIndex = sitemapIndexGenerator.toPrettyString(2);
String expectedSitemapIndex = "<sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n" +
" <sitemap>\n" +
" <loc>http://javalibs.com/sitemap-archetypes.xml</loc>\n" +
" <lastmod>2018-01-01</lastmod>\n" +
" </sitemap>\n" +
" <sitemap>\n" +
" <loc>http://javalibs.com/sitemap-plugins.xml</loc>\n" +
" <lastmod>2018-01-01</lastmod>\n" +
" </sitemap>\n" +
"</sitemapindex>\n";
assertEquals(expectedSitemapIndex, actualSitemapIndex);
}

@Test
Expand Down

0 comments on commit f8c41ad

Please sign in to comment.