Skip to content

Commit f8c41ad

Browse files
jirka.pinkas@gmail.comjirka.pinkas@gmail.com
authored andcommitted
added toPrettyString(indent) method to sitemap generators
1 parent 8801cb5 commit f8c41ad

File tree

3 files changed

+114
-19
lines changed

3 files changed

+114
-19
lines changed

src/main/java/cz/jiripinkas/jsitemapgenerator/AbstractGenerator.java

Lines changed: 85 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,26 @@
11
package cz.jiripinkas.jsitemapgenerator;
22

33
import cz.jiripinkas.jsitemapgenerator.exception.InvalidUrlException;
4+
import org.w3c.dom.Document;
5+
import org.w3c.dom.Node;
6+
import org.w3c.dom.NodeList;
7+
import org.xml.sax.InputSource;
48

9+
import javax.xml.XMLConstants;
10+
import javax.xml.parsers.DocumentBuilderFactory;
11+
import javax.xml.transform.OutputKeys;
12+
import javax.xml.transform.Transformer;
13+
import javax.xml.transform.TransformerFactory;
14+
import javax.xml.transform.dom.DOMSource;
15+
import javax.xml.transform.stream.StreamResult;
16+
import javax.xml.xpath.XPath;
17+
import javax.xml.xpath.XPathConstants;
18+
import javax.xml.xpath.XPathFactory;
19+
import java.io.ByteArrayInputStream;
20+
import java.io.StringWriter;
521
import java.net.MalformedURLException;
622
import java.net.URL;
23+
import java.nio.charset.StandardCharsets;
724
import java.util.Collection;
825
import java.util.Map;
926
import java.util.TreeMap;
@@ -12,9 +29,10 @@
1229

1330
/**
1431
* Abstract Generator
32+
*
1533
* @param <I> Concrete implementation of AbstractGenerator, for example SitemapGenerator
1634
*/
17-
public abstract class AbstractGenerator <I extends AbstractGenerator> {
35+
public abstract class AbstractGenerator<I extends AbstractGenerator> {
1836

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

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

7694
/**
7795
* Add single page to sitemap.
96+
*
7897
* @param supplier Supplier method which sneaks any checked exception
7998
* https://www.baeldung.com/java-sneaky-throws
8099
* Allows for calling method which performs some operation and then returns name of page.
@@ -93,6 +112,7 @@ public I addPage(StringSupplierWithException<String> supplier) {
93112
/**
94113
* This method is called before adding a page to urls.
95114
* It can be used to change webPage attributes
115+
*
96116
* @param webPage WebPage
97117
*/
98118
protected void beforeAddPageEvent(WebPage webPage) {
@@ -128,9 +148,9 @@ public I addPages(Supplier<Collection<WebPage>> webPagesSupplier) {
128148
/**
129149
* Add collection of pages to sitemap
130150
*
131-
* @param <T> This is the type parameter
151+
* @param <T> This is the type parameter
132152
* @param webPages Collection of pages
133-
* @param mapper Mapper function which transforms some object to WebPage
153+
* @param mapper Mapper function which transforms some object to WebPage
134154
* @return this
135155
*/
136156
public <T> I addPages(Collection<T> webPages, Function<T, WebPage> mapper) {
@@ -143,9 +163,9 @@ public <T> I addPages(Collection<T> webPages, Function<T, WebPage> mapper) {
143163
/**
144164
* Add collection of pages to sitemap
145165
*
146-
* @param <T> This is the type parameter
166+
* @param <T> This is the type parameter
147167
* @param webPages Collection of pages
148-
* @param mapper Mapper function which transforms some object to String. This will be passed to WebPage.of(name)
168+
* @param mapper Mapper function which transforms some object to String. This will be passed to WebPage.of(name)
149169
* @return this
150170
*/
151171
public <T> I addPageNames(Collection<T> webPages, Function<T, String> mapper) {
@@ -158,9 +178,9 @@ public <T> I addPageNames(Collection<T> webPages, Function<T, String> mapper) {
158178
/**
159179
* Add collection of pages to sitemap
160180
*
161-
* @param <T> This is the type parameter
181+
* @param <T> This is the type parameter
162182
* @param webPagesSupplier Collection of pages supplier
163-
* @param mapper Mapper function which transforms some object to WebPage
183+
* @param mapper Mapper function which transforms some object to WebPage
164184
* @return this
165185
*/
166186
public <T> I addPages(Supplier<Collection<T>> webPagesSupplier, Function<T, WebPage> mapper) {
@@ -173,9 +193,9 @@ public <T> I addPages(Supplier<Collection<T>> webPagesSupplier, Function<T, WebP
173193
/**
174194
* Add collection of pages to sitemap
175195
*
176-
* @param <T> This is the type parameter
196+
* @param <T> This is the type parameter
177197
* @param webPagesSupplier Collection of pages supplier
178-
* @param mapper Mapper function which transforms some object to String. This will be passed to WebPage.of(name)
198+
* @param mapper Mapper function which transforms some object to String. This will be passed to WebPage.of(name)
179199
* @return this
180200
*/
181201
public <T> I addPageNames(Supplier<Collection<T>> webPagesSupplier, Function<T, String> mapper) {
@@ -187,13 +207,14 @@ public <T> I addPageNames(Supplier<Collection<T>> webPagesSupplier, Function<T,
187207

188208
/**
189209
* Run some method
210+
*
190211
* @param runnable Runnable method which sneaks any checked exception
191212
* https://www.baeldung.com/java-sneaky-throws
192213
* Usage:
193214
* SitemapIndexGenerator.of(homepage)
194-
* .run(() -&gt; methodToCall())
195-
* .addPage(WebPage.of("test))
196-
* .toString()
215+
* .run(() -&gt; methodToCall())
216+
* .addPage(WebPage.of("test))
217+
* .toString()
197218
* @return this
198219
*/
199220
public I run(RunnableWithException runnable) {
@@ -208,13 +229,14 @@ public I run(RunnableWithException runnable) {
208229
/**
209230
* Run some method. Argument is current generator,
210231
* which allows to access current generator in run() method.
232+
*
211233
* @param consumer Consumer method which sneaks any checked exception
212234
* https://www.baeldung.com/java-sneaky-throws
213235
* Usage:
214236
* SitemapIndexGenerator.of(homepage)
215-
* .run(currentGenerator -&gt; { ... })
216-
* .addPage(WebPage.of("test))
217-
* .toString()
237+
* .run(currentGenerator -&gt; { ... })
238+
* .addPage(WebPage.of("test))
239+
* .toString()
218240
* @return this
219241
*/
220242
public I run(GeneratorConsumerWithException<I> consumer) {
@@ -229,7 +251,7 @@ public I run(GeneratorConsumerWithException<I> consumer) {
229251

230252
@SuppressWarnings("unchecked")
231253
protected I getThis() {
232-
return (I)this;
254+
return (I) this;
233255
}
234256

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

247269
/**
248270
* Sneak exception https://www.baeldung.com/java-sneaky-throws
249-
* @param e Exception
271+
*
272+
* @param e Exception
250273
* @param <E> Type parameter
251274
* @throws E Sneaked exception
252275
*/
@@ -255,4 +278,49 @@ private static <E extends Throwable> void sneakyThrow(Throwable e) throws E {
255278
throw (E) e;
256279
}
257280

281+
/**
282+
* Method to prettify XML string
283+
* @param xml Input XML
284+
* @param indent Ident
285+
* @return Prettified XML
286+
*/
287+
protected String toPrettyXmlString(String xml, int indent) {
288+
try {
289+
// Turn xml string into a document
290+
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
291+
documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
292+
Document document = documentBuilderFactory
293+
.newDocumentBuilder()
294+
.parse(new InputSource(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))));
295+
296+
// Remove whitespaces outside tags
297+
document.normalize();
298+
XPath xPath = XPathFactory.newInstance().newXPath();
299+
NodeList nodeList = (NodeList) xPath.evaluate("//text()[normalize-space()='']",
300+
document,
301+
XPathConstants.NODESET);
302+
303+
for (int i = 0; i < nodeList.getLength(); ++i) {
304+
Node node = nodeList.item(i);
305+
node.getParentNode().removeChild(node);
306+
}
307+
308+
// Setup pretty print options
309+
TransformerFactory transformerFactory = TransformerFactory.newInstance();
310+
transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
311+
transformerFactory.setAttribute("indent-number", indent);
312+
Transformer transformer = transformerFactory.newTransformer();
313+
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
314+
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
315+
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
316+
317+
// Return pretty print xml string
318+
StringWriter stringWriter = new StringWriter();
319+
transformer.transform(new DOMSource(document), new StreamResult(stringWriter));
320+
return stringWriter.toString();
321+
} catch (Exception e) {
322+
throw new RuntimeException(e);
323+
}
324+
}
325+
258326
}

src/main/java/cz/jiripinkas/jsitemapgenerator/AbstractSitemapGenerator.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@ public String toString() {
5050
return result.toString();
5151
}
5252

53+
/**
54+
* Construct sitemap into single prettified String
55+
* @param indent
56+
* @return
57+
*/
58+
public String toPrettyString(int indent) {
59+
return toPrettyXmlString(toString(), indent).replace("\r\n", "\n");
60+
}
61+
5362
private ByteArrayOutputStream gzipIt(InputStream inputStream) {
5463
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
5564
byte[] buffer = new byte[1024];

src/test/java/cz/jiripinkas/jsitemapgenerator/AbstractSitemapGeneratorTest.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import org.junit.Before;
55
import org.junit.Test;
66

7+
import java.time.LocalDateTime;
8+
79
import static org.junit.Assert.*;
810

911
public class AbstractSitemapGeneratorTest {
@@ -13,8 +15,24 @@ public class AbstractSitemapGeneratorTest {
1315
@Before
1416
public void setUp() {
1517
sitemapIndexGenerator = SitemapIndexGenerator.of("http://javalibs.com");
16-
sitemapIndexGenerator.addPage(WebPage.builder().name("sitemap-plugins.xml").lastModNow().build());
17-
sitemapIndexGenerator.addPage(WebPage.builder().name("sitemap-archetypes.xml").lastModNow().build());
18+
sitemapIndexGenerator.addPage(WebPage.builder().name("sitemap-plugins.xml").lastMod(LocalDateTime.of(2018, 1, 1, 0, 0)).build());
19+
sitemapIndexGenerator.addPage(WebPage.builder().name("sitemap-archetypes.xml").lastMod(LocalDateTime.of(2018, 1, 1, 0, 0)).build());
20+
}
21+
22+
@Test
23+
public void toPrettyString() {
24+
String actualSitemapIndex = sitemapIndexGenerator.toPrettyString(2);
25+
String expectedSitemapIndex = "<sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n" +
26+
" <sitemap>\n" +
27+
" <loc>http://javalibs.com/sitemap-archetypes.xml</loc>\n" +
28+
" <lastmod>2018-01-01</lastmod>\n" +
29+
" </sitemap>\n" +
30+
" <sitemap>\n" +
31+
" <loc>http://javalibs.com/sitemap-plugins.xml</loc>\n" +
32+
" <lastmod>2018-01-01</lastmod>\n" +
33+
" </sitemap>\n" +
34+
"</sitemapindex>\n";
35+
assertEquals(expectedSitemapIndex, actualSitemapIndex);
1836
}
1937

2038
@Test

0 commit comments

Comments
 (0)