1
1
package cz .jiripinkas .jsitemapgenerator ;
2
2
3
3
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 ;
4
8
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 ;
5
21
import java .net .MalformedURLException ;
6
22
import java .net .URL ;
23
+ import java .nio .charset .StandardCharsets ;
7
24
import java .util .Collection ;
8
25
import java .util .Map ;
9
26
import java .util .TreeMap ;
12
29
13
30
/**
14
31
* Abstract Generator
32
+ *
15
33
* @param <I> Concrete implementation of AbstractGenerator, for example SitemapGenerator
16
34
*/
17
- public abstract class AbstractGenerator <I extends AbstractGenerator > {
35
+ public abstract class AbstractGenerator <I extends AbstractGenerator > {
18
36
19
37
protected Map <String , WebPage > urls = new TreeMap <>();
20
38
@@ -75,6 +93,7 @@ public I addPage(String name) {
75
93
76
94
/**
77
95
* Add single page to sitemap.
96
+ *
78
97
* @param supplier Supplier method which sneaks any checked exception
79
98
* https://www.baeldung.com/java-sneaky-throws
80
99
* Allows for calling method which performs some operation and then returns name of page.
@@ -93,6 +112,7 @@ public I addPage(StringSupplierWithException<String> supplier) {
93
112
/**
94
113
* This method is called before adding a page to urls.
95
114
* It can be used to change webPage attributes
115
+ *
96
116
* @param webPage WebPage
97
117
*/
98
118
protected void beforeAddPageEvent (WebPage webPage ) {
@@ -128,9 +148,9 @@ public I addPages(Supplier<Collection<WebPage>> webPagesSupplier) {
128
148
/**
129
149
* Add collection of pages to sitemap
130
150
*
131
- * @param <T> This is the type parameter
151
+ * @param <T> This is the type parameter
132
152
* @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
134
154
* @return this
135
155
*/
136
156
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) {
143
163
/**
144
164
* Add collection of pages to sitemap
145
165
*
146
- * @param <T> This is the type parameter
166
+ * @param <T> This is the type parameter
147
167
* @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)
149
169
* @return this
150
170
*/
151
171
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) {
158
178
/**
159
179
* Add collection of pages to sitemap
160
180
*
161
- * @param <T> This is the type parameter
181
+ * @param <T> This is the type parameter
162
182
* @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
164
184
* @return this
165
185
*/
166
186
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
173
193
/**
174
194
* Add collection of pages to sitemap
175
195
*
176
- * @param <T> This is the type parameter
196
+ * @param <T> This is the type parameter
177
197
* @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)
179
199
* @return this
180
200
*/
181
201
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,
187
207
188
208
/**
189
209
* Run some method
210
+ *
190
211
* @param runnable Runnable method which sneaks any checked exception
191
212
* https://www.baeldung.com/java-sneaky-throws
192
213
* Usage:
193
214
* SitemapIndexGenerator.of(homepage)
194
- * .run(() -> methodToCall())
195
- * .addPage(WebPage.of("test))
196
- * .toString()
215
+ * .run(() -> methodToCall())
216
+ * .addPage(WebPage.of("test))
217
+ * .toString()
197
218
* @return this
198
219
*/
199
220
public I run (RunnableWithException runnable ) {
@@ -208,13 +229,14 @@ public I run(RunnableWithException runnable) {
208
229
/**
209
230
* Run some method. Argument is current generator,
210
231
* which allows to access current generator in run() method.
232
+ *
211
233
* @param consumer Consumer method which sneaks any checked exception
212
234
* https://www.baeldung.com/java-sneaky-throws
213
235
* Usage:
214
236
* SitemapIndexGenerator.of(homepage)
215
- * .run(currentGenerator -> { ... })
216
- * .addPage(WebPage.of("test))
217
- * .toString()
237
+ * .run(currentGenerator -> { ... })
238
+ * .addPage(WebPage.of("test))
239
+ * .toString()
218
240
* @return this
219
241
*/
220
242
public I run (GeneratorConsumerWithException <I > consumer ) {
@@ -229,7 +251,7 @@ public I run(GeneratorConsumerWithException<I> consumer) {
229
251
230
252
@ SuppressWarnings ("unchecked" )
231
253
protected I getThis () {
232
- return (I )this ;
254
+ return (I ) this ;
233
255
}
234
256
235
257
public interface RunnableWithException {
@@ -246,7 +268,8 @@ public interface StringSupplierWithException<S> {
246
268
247
269
/**
248
270
* Sneak exception https://www.baeldung.com/java-sneaky-throws
249
- * @param e Exception
271
+ *
272
+ * @param e Exception
250
273
* @param <E> Type parameter
251
274
* @throws E Sneaked exception
252
275
*/
@@ -255,4 +278,49 @@ private static <E extends Throwable> void sneakyThrow(Throwable e) throws E {
255
278
throw (E ) e ;
256
279
}
257
280
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
+
258
326
}
0 commit comments