Clean + lint
This commit is contained in:
parent
ce92e1fae9
commit
66878900f5
18
.editorconfig
Normal file
18
.editorconfig
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.{kt, kts}]
|
||||||
|
indent_size = 4
|
||||||
|
insert_final_newline = true
|
||||||
|
continuation_indent_size=4
|
||||||
|
max_line_length = 120
|
||||||
|
disabled_rules = no-wildcard-imports
|
||||||
|
kotlin_imports_layout = idea
|
||||||
6
pom.xml
6
pom.xml
@ -10,6 +10,7 @@
|
|||||||
<maven.compiler.source>11</maven.compiler.source>
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<kotlin.version>1.4.10</kotlin.version>
|
<kotlin.version>1.4.10</kotlin.version>
|
||||||
|
<kotlin.code.style>official</kotlin.code.style>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
@ -51,6 +52,11 @@
|
|||||||
<artifactId>koin-core</artifactId>
|
<artifactId>koin-core</artifactId>
|
||||||
<version>2.1.6</version>
|
<version>2.1.6</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
<version>1.7.30</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@ -4,9 +4,9 @@ import com.electronwill.nightconfig.core.file.FileConfig
|
|||||||
import com.electronwill.nightconfig.core.Config as NightConfig
|
import com.electronwill.nightconfig.core.Config as NightConfig
|
||||||
|
|
||||||
data class StarterConfig(
|
data class StarterConfig(
|
||||||
val dependencies: List<Dependency>,
|
val dependencies: List<Dependency>,
|
||||||
val inputs: List<Input>,
|
val inputs: List<Input>,
|
||||||
val repositories: List<Repository>,
|
val repositories: List<Repository>,
|
||||||
)
|
)
|
||||||
|
|
||||||
class Config {
|
class Config {
|
||||||
@ -19,31 +19,30 @@ class Config {
|
|||||||
cfg.load()
|
cfg.load()
|
||||||
|
|
||||||
val dependencies = cfg.configMap("dependencies")
|
val dependencies = cfg.configMap("dependencies")
|
||||||
.map { (name, values) ->
|
.map { (name, values) ->
|
||||||
Dependency(
|
Dependency(
|
||||||
name,
|
name,
|
||||||
values["groupId"],
|
values["groupId"],
|
||||||
values["artifactId"],
|
values["artifactId"],
|
||||||
values["version"],
|
values["version"],
|
||||||
values.getOrElse("default", false),
|
values.getOrElse("default", false),
|
||||||
values.getEnumOrElse("category", Category.Other),
|
values.getEnumOrElse("category", Category.Other),
|
||||||
values.getEnumOrElse("scope", Scope.Compile),
|
values.getEnumOrElse("scope", Scope.Compile),
|
||||||
values["logger"],
|
values["logger"],
|
||||||
values["repository"],
|
values["repository"],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val inputs = cfg.configMap("inputs")
|
val inputs = cfg.configMap("inputs")
|
||||||
.map { (name, values) ->
|
.map { (name, values) ->
|
||||||
Input(name, values["display"], values["default"])
|
Input(name, values["display"], values["default"])
|
||||||
}
|
}
|
||||||
|
|
||||||
val repositories = cfg.configMap("repositories")
|
val repositories = cfg.configMap("repositories")
|
||||||
.map { (name, values) ->
|
.map { (name, values) ->
|
||||||
Repository(name, values["url"])
|
Repository(name, values["url"])
|
||||||
}
|
}
|
||||||
|
|
||||||
return StarterConfig(dependencies, inputs, repositories)
|
return StarterConfig(dependencies, inputs, repositories)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,32 @@
|
|||||||
package starter
|
package starter
|
||||||
|
|
||||||
|
import org.http4k.routing.ResourceLoader
|
||||||
|
import org.http4k.routing.RoutingHttpHandler
|
||||||
|
import org.http4k.routing.routes
|
||||||
|
import org.http4k.routing.static
|
||||||
|
import org.http4k.server.SunHttp
|
||||||
|
import org.http4k.server.asServer
|
||||||
import org.koin.core.context.startKoin
|
import org.koin.core.context.startKoin
|
||||||
import org.koin.dsl.bind
|
import org.koin.dsl.bind
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
import org.koin.dsl.onClose
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import starter.routes.IndexRouteSupplier
|
||||||
|
import starter.routes.RouteSupplier
|
||||||
|
import starter.routes.ZipRouteSupplier
|
||||||
|
import starter.routes.toRouter
|
||||||
import starter.templates.*
|
import starter.templates.*
|
||||||
|
|
||||||
val mainModule = module {
|
val mainModule = module {
|
||||||
|
single(createdAtStart = true) {
|
||||||
|
get<Logger>().info("Starting on http://localhost:7000")
|
||||||
|
get<RoutingHttpHandler>().asServer(SunHttp(7000)).start()
|
||||||
|
} onClose { it?.stop() }
|
||||||
|
|
||||||
single { Config().load() }
|
single { Config().load() }
|
||||||
single { PebbleModule().engine() }
|
single { PebbleModule().engine() }
|
||||||
single { Server(get(), get(), get()) }
|
single { LoggerFactory.getLogger("Starter") }
|
||||||
single { Views(get()) }
|
single { Views(get()) }
|
||||||
single { ProjectZip(getAll()) }
|
single { ProjectZip(getAll()) }
|
||||||
}
|
}
|
||||||
@ -20,10 +38,19 @@ val templateModule = module {
|
|||||||
single { GitignoreTemplate(get()) } bind Template::class
|
single { GitignoreTemplate(get()) } bind Template::class
|
||||||
}
|
}
|
||||||
|
|
||||||
fun main() {
|
val routesModule = module {
|
||||||
val koin = startKoin {
|
single { IndexRouteSupplier(get(), get()) } bind RouteSupplier::class
|
||||||
modules(mainModule, templateModule)
|
single { ZipRouteSupplier(get(), get()) } bind RouteSupplier::class
|
||||||
}.koin
|
single {
|
||||||
val server = koin.get<Server>()
|
routes(
|
||||||
server.run()
|
static(ResourceLoader.Classpath("/assets")),
|
||||||
|
getAll<RouteSupplier>().toRouter()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
startKoin {
|
||||||
|
modules(mainModule, templateModule, routesModule)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,15 +9,15 @@ enum class Scope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class Dependency(
|
data class Dependency(
|
||||||
val name: String,
|
val name: String,
|
||||||
val groupId: String,
|
val groupId: String,
|
||||||
val artifactId: String,
|
val artifactId: String,
|
||||||
val version: String,
|
val version: String,
|
||||||
val default: Boolean,
|
val default: Boolean,
|
||||||
val category: Category,
|
val category: Category,
|
||||||
val scope: Scope,
|
val scope: Scope,
|
||||||
val logger: String?,
|
val logger: String?,
|
||||||
val repository: String?,
|
val repository: String?,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class Repository(val name: String, val url: String)
|
data class Repository(val name: String, val url: String)
|
||||||
@ -25,9 +25,9 @@ data class Repository(val name: String, val url: String)
|
|||||||
data class Input(val name: String, val display: String, val value: String? = null)
|
data class Input(val name: String, val display: String, val value: String? = null)
|
||||||
|
|
||||||
data class Project(
|
data class Project(
|
||||||
val name: String,
|
val name: String,
|
||||||
val basePackage: String,
|
val basePackage: String,
|
||||||
val inputs: List<Input>,
|
val inputs: List<Input>,
|
||||||
val dependencies: List<Dependency>,
|
val dependencies: List<Dependency>,
|
||||||
val repositories: List<Repository>,
|
val repositories: List<Repository>,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -8,8 +8,8 @@ class PebbleModule {
|
|||||||
val loader = ClasspathLoader()
|
val loader = ClasspathLoader()
|
||||||
loader.suffix = ".twig"
|
loader.suffix = ".twig"
|
||||||
return PebbleEngine.Builder()
|
return PebbleEngine.Builder()
|
||||||
.loader(loader)
|
.loader(loader)
|
||||||
.cacheActive(true)
|
.cacheActive(true)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,5 +17,4 @@ class ProjectZip(private val templates: List<Template>) {
|
|||||||
}
|
}
|
||||||
return zipOutput.outputStream
|
return zipOutput.outputStream
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,68 +0,0 @@
|
|||||||
package starter
|
|
||||||
|
|
||||||
import org.http4k.core.HttpHandler
|
|
||||||
import org.http4k.core.Method
|
|
||||||
import org.http4k.core.Response
|
|
||||||
import org.http4k.core.Status
|
|
||||||
import org.http4k.core.body.form
|
|
||||||
import org.http4k.core.body.formAsMap
|
|
||||||
import org.http4k.routing.ResourceLoader
|
|
||||||
import org.http4k.routing.bind
|
|
||||||
import org.http4k.routing.routes
|
|
||||||
import org.http4k.routing.static
|
|
||||||
import org.http4k.server.SunHttp
|
|
||||||
import org.http4k.server.asServer
|
|
||||||
import starter.utils.sanitizeFilename
|
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
|
|
||||||
class Server(
|
|
||||||
private val views: Views,
|
|
||||||
private val conf: StarterConfig,
|
|
||||||
private val projectZip: ProjectZip,
|
|
||||||
) {
|
|
||||||
|
|
||||||
fun run() {
|
|
||||||
val indexHandler: HttpHandler = {
|
|
||||||
Response(Status.OK).body(views.index(conf.dependencies, conf.inputs)).header("Content-Type", "text/html")
|
|
||||||
}
|
|
||||||
val zipHandler: HttpHandler = { req ->
|
|
||||||
val deps = conf.dependencies.filter {
|
|
||||||
req.form(it.name) != null
|
|
||||||
}
|
|
||||||
|
|
||||||
val inputKeys = conf.inputs.map { it.name }
|
|
||||||
val inputs = req.formAsMap()
|
|
||||||
.filter { it.key in inputKeys }
|
|
||||||
.map { (name, value) ->
|
|
||||||
conf.inputs.find { it.name == name }!!.copy(value = value.first())
|
|
||||||
}
|
|
||||||
|
|
||||||
val projectName = inputs.find { it.name == "name" }!!.value!!
|
|
||||||
val basePackage = inputs.find { it.name == "basePackage" }!!.value!!
|
|
||||||
|
|
||||||
if (basePackage.contains("/") || basePackage.contains("..")) {
|
|
||||||
Response(Status.BAD_REQUEST).body("Invalid Base Package")
|
|
||||||
} else {
|
|
||||||
val repositories = conf.repositories
|
|
||||||
.filter { repo -> repo.name in deps.mapNotNull { it.repository } }
|
|
||||||
|
|
||||||
val project = Project(projectName, basePackage, inputs, deps, repositories)
|
|
||||||
val outputStream = projectZip.createZip(project)
|
|
||||||
|
|
||||||
Response(Status.OK).header("Content-Type", "application/zip")
|
|
||||||
.header("Content-Disposition", "attachment; filename=\"${sanitizeFilename(projectName)}.zip\"")
|
|
||||||
.body(ByteArrayInputStream(outputStream.toByteArray()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val app = routes(
|
|
||||||
"/" bind Method.GET to indexHandler,
|
|
||||||
"/" bind Method.POST to zipHandler,
|
|
||||||
static(ResourceLoader.Classpath("/assets"))
|
|
||||||
)
|
|
||||||
|
|
||||||
app.asServer(SunHttp(7000)).start()
|
|
||||||
println("Started on http://localhost:7000")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,17 +1,14 @@
|
|||||||
package starter
|
package starter
|
||||||
|
|
||||||
import com.mitchellbosecke.pebble.PebbleEngine
|
import com.mitchellbosecke.pebble.PebbleEngine
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import starter.utils.render
|
import starter.utils.render
|
||||||
|
|
||||||
class Views(private val engine: PebbleEngine) {
|
class Views(private val engine: PebbleEngine) {
|
||||||
private val logger = LoggerFactory.getLogger(javaClass)
|
|
||||||
|
|
||||||
fun index(dependencies: List<Dependency>, inputs: List<Input>): String {
|
fun index(dependencies: List<Dependency>, inputs: List<Input>): String {
|
||||||
val dependenciesByCategory = dependencies.groupBy { it.category }.toSortedMap()
|
val dependenciesByCategory = dependencies.groupBy { it.category }.toSortedMap()
|
||||||
return engine.render("views/index",
|
return engine.render(
|
||||||
mapOf("dependencies" to dependenciesByCategory, "inputs" to inputs)
|
"views/index",
|
||||||
|
mapOf("dependencies" to dependenciesByCategory, "inputs" to inputs)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
17
src/main/kotlin/starter/extensions/Http4kExtensions.kt
Normal file
17
src/main/kotlin/starter/extensions/Http4kExtensions.kt
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
@file:Suppress("NOTHING_TO_INLINE")
|
||||||
|
|
||||||
|
package starter.extensions
|
||||||
|
|
||||||
|
import org.http4k.core.Response
|
||||||
|
import org.http4k.core.Status
|
||||||
|
import starter.utils.sanitizeFilename
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
|
inline fun Response.Companion.ok() = Response(Status.OK)
|
||||||
|
inline fun Response.Companion.badRequest() = Response(Status.BAD_REQUEST)
|
||||||
|
|
||||||
|
fun attachment(value: InputStream, name: String, contentType: String) = { res: Response ->
|
||||||
|
res.header("Content-Type", contentType)
|
||||||
|
.header("Content-Disposition", "attachment; filename=\"${sanitizeFilename(name)}\"")
|
||||||
|
.body(value)
|
||||||
|
}
|
||||||
19
src/main/kotlin/starter/routes/IndexRouteSupplier.kt
Normal file
19
src/main/kotlin/starter/routes/IndexRouteSupplier.kt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package starter.routes
|
||||||
|
|
||||||
|
import org.http4k.core.Method
|
||||||
|
import org.http4k.core.Response
|
||||||
|
import org.http4k.core.Status
|
||||||
|
import org.http4k.routing.bind
|
||||||
|
import starter.StarterConfig
|
||||||
|
import starter.Views
|
||||||
|
|
||||||
|
class IndexRouteSupplier(
|
||||||
|
private val views: Views,
|
||||||
|
private val conf: StarterConfig,
|
||||||
|
) : RouteSupplier {
|
||||||
|
override fun get() = "/" bind Method.GET to {
|
||||||
|
Response(Status.OK)
|
||||||
|
.body(views.index(conf.dependencies, conf.inputs))
|
||||||
|
.header("Content-Type", "text/html")
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/main/kotlin/starter/routes/RouteSupplier.kt
Normal file
10
src/main/kotlin/starter/routes/RouteSupplier.kt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package starter.routes
|
||||||
|
|
||||||
|
import org.http4k.routing.RoutingHttpHandler
|
||||||
|
import org.http4k.routing.routes
|
||||||
|
|
||||||
|
interface RouteSupplier {
|
||||||
|
fun get(): RoutingHttpHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
fun List<RouteSupplier>.toRouter() = routes(*map { it.get() }.toTypedArray())
|
||||||
56
src/main/kotlin/starter/routes/ZipRouteSupplier.kt
Normal file
56
src/main/kotlin/starter/routes/ZipRouteSupplier.kt
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package starter.routes
|
||||||
|
|
||||||
|
import org.http4k.core.Method
|
||||||
|
import org.http4k.core.Response
|
||||||
|
import org.http4k.core.body.form
|
||||||
|
import org.http4k.core.body.formAsMap
|
||||||
|
import org.http4k.core.with
|
||||||
|
import org.http4k.routing.bind
|
||||||
|
import starter.Project
|
||||||
|
import starter.ProjectZip
|
||||||
|
import starter.StarterConfig
|
||||||
|
import starter.extensions.attachment
|
||||||
|
import starter.extensions.badRequest
|
||||||
|
import starter.extensions.ok
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
|
||||||
|
class ZipRouteSupplier(
|
||||||
|
private val conf: StarterConfig,
|
||||||
|
private val projectZip: ProjectZip,
|
||||||
|
) : RouteSupplier {
|
||||||
|
|
||||||
|
override fun get() = "/" bind Method.POST to { req ->
|
||||||
|
|
||||||
|
val deps = conf.dependencies.filter {
|
||||||
|
req.form(it.name) != null
|
||||||
|
}
|
||||||
|
|
||||||
|
val inputKeys = conf.inputs.map { it.name }
|
||||||
|
val inputs = req.formAsMap()
|
||||||
|
.filter { it.key in inputKeys }
|
||||||
|
.map { (name, value) ->
|
||||||
|
conf.inputs.find { it.name == name }!!.copy(value = value.first())
|
||||||
|
}
|
||||||
|
|
||||||
|
val projectName = inputs.find { it.name == "name" }!!.value!!
|
||||||
|
val basePackage = inputs.find { it.name == "basePackage" }!!.value!!
|
||||||
|
|
||||||
|
if (basePackage.contains("/") || basePackage.contains("..")) {
|
||||||
|
Response.badRequest()
|
||||||
|
} else {
|
||||||
|
val repositories = conf.repositories
|
||||||
|
.filter { repo -> repo.name in deps.mapNotNull { it.repository } }
|
||||||
|
|
||||||
|
val project = Project(projectName, basePackage, inputs, deps, repositories)
|
||||||
|
val outputStream = projectZip.createZip(project)
|
||||||
|
|
||||||
|
Response.ok().with(
|
||||||
|
attachment(
|
||||||
|
value = ByteArrayInputStream(outputStream.toByteArray()),
|
||||||
|
name = "$projectName.zip",
|
||||||
|
contentType = "application/zip"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,8 +6,8 @@ import starter.utils.render
|
|||||||
|
|
||||||
class GitignoreTemplate(private val engine: PebbleEngine) : Template {
|
class GitignoreTemplate(private val engine: PebbleEngine) : Template {
|
||||||
override fun path(project: Project) =
|
override fun path(project: Project) =
|
||||||
".gitignore"
|
".gitignore"
|
||||||
|
|
||||||
override fun render(project: Project) =
|
override fun render(project: Project) =
|
||||||
engine.render("starter/gitignore/index")
|
engine.render("starter/gitignore/index")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ class LogbackTemplate(private val engine: PebbleEngine) : Template {
|
|||||||
|
|
||||||
override fun render(project: Project): String {
|
override fun render(project: Project): String {
|
||||||
val args = mapOf(
|
val args = mapOf(
|
||||||
"loggers" to project.dependencies.mapNotNull { it.logger }.toSet()
|
"loggers" to project.dependencies.mapNotNull { it.logger }.toSet()
|
||||||
)
|
)
|
||||||
val rendered = engine.render("starter/logback/index", args)
|
val rendered = engine.render("starter/logback/index", args)
|
||||||
return prettyPrintXml(rendered)
|
return prettyPrintXml(rendered)
|
||||||
|
|||||||
@ -6,8 +6,8 @@ import starter.utils.render
|
|||||||
|
|
||||||
class MainTemplate(private val engine: PebbleEngine) : Template {
|
class MainTemplate(private val engine: PebbleEngine) : Template {
|
||||||
override fun path(project: Project) =
|
override fun path(project: Project) =
|
||||||
"src/main/kotlin/" + project.basePackage.replace('.', '/') + "/" + project.name.toLowerCase().capitalize() + ".kt"
|
"src/main/kotlin/" + project.basePackage.replace('.', '/') + "/" + project.name.toLowerCase().capitalize() + ".kt"
|
||||||
|
|
||||||
override fun render(project: Project) =
|
override fun render(project: Project) =
|
||||||
engine.render("starter/main/index", mapOf("basePackage" to project.basePackage))
|
engine.render("starter/main/index", mapOf("basePackage" to project.basePackage))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,9 +10,9 @@ class PomTemplate(private val engine: PebbleEngine) : Template {
|
|||||||
|
|
||||||
override fun render(project: Project): String {
|
override fun render(project: Project): String {
|
||||||
val args: MutableMap<String, Any?> = mutableMapOf(
|
val args: MutableMap<String, Any?> = mutableMapOf(
|
||||||
"dependencies" to project.dependencies.sortedBy { it.scope },
|
"dependencies" to project.dependencies.sortedBy { it.scope },
|
||||||
"repositories" to project.repositories,
|
"repositories" to project.repositories,
|
||||||
"kotlinxSerialization" to project.dependencies.any { it.name == "Kotlinx-serialization" },
|
"kotlinxSerialization" to project.dependencies.any { it.name == "Kotlinx-serialization" },
|
||||||
)
|
)
|
||||||
|
|
||||||
project.inputs.forEach {
|
project.inputs.forEach {
|
||||||
|
|||||||
@ -13,22 +13,23 @@ import javax.xml.transform.stream.StreamResult
|
|||||||
import javax.xml.xpath.XPathConstants
|
import javax.xml.xpath.XPathConstants
|
||||||
import javax.xml.xpath.XPathFactory
|
import javax.xml.xpath.XPathFactory
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@see https://stackoverflow.com/a/33541820
|
@see https://stackoverflow.com/a/33541820
|
||||||
*/
|
*/
|
||||||
fun prettyPrintXml(xml: String, indent: Int = 4): String {
|
fun prettyPrintXml(xml: String, indent: Int = 4): String {
|
||||||
// Turn xml string into a document
|
// Turn xml string into a document
|
||||||
val document: Document = DocumentBuilderFactory.newInstance()
|
val document: Document = DocumentBuilderFactory.newInstance()
|
||||||
.newDocumentBuilder()
|
.newDocumentBuilder()
|
||||||
.parse(InputSource(ByteArrayInputStream(xml.encodeToByteArray())))
|
.parse(InputSource(ByteArrayInputStream(xml.encodeToByteArray())))
|
||||||
|
|
||||||
// Remove whitespaces outside tags
|
// Remove whitespaces outside tags
|
||||||
document.normalize()
|
document.normalize()
|
||||||
val xPath = XPathFactory.newInstance().newXPath()
|
val xPath = XPathFactory.newInstance().newXPath()
|
||||||
val nodeList = xPath.evaluate("//text()[normalize-space()='']",
|
val nodeList = xPath.evaluate(
|
||||||
document,
|
"//text()[normalize-space()='']",
|
||||||
XPathConstants.NODESET) as NodeList
|
document,
|
||||||
|
XPathConstants.NODESET
|
||||||
|
) as NodeList
|
||||||
for (i in 0 until nodeList.length) {
|
for (i in 0 until nodeList.length) {
|
||||||
val node = nodeList.item(i)
|
val node = nodeList.item(i)
|
||||||
node.parentNode.removeChild(node)
|
node.parentNode.removeChild(node)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user