1
0
mirror of https://github.com/alexandrev/xslt-lab.git synced 2026-09-20 12:33:14 +00:00

Initial version

This commit is contained in:
2025-07-01 09:00:24 +02:00
committed by alexandrev-tibco
parent 6ac97bd80c
commit 3268dbca4e
3 changed files with 165 additions and 0 deletions
+35
View File
@@ -0,0 +1,35 @@
# Etapa de build
FROM golang:1.21-alpine AS builder
# Instalar dependencias necesarias
RUN apk add --no-cache git
# Establecer directorio de trabajo
WORKDIR /app/src
# Copiar los archivos
COPY src/ .
# Compilar el binario estático
RUN go mod init xslt-playground && \
go get github.com/gin-gonic/gin && \
go build -o server .
# Etapa final (runtime)
FROM alpine:latest
# Instalar Java (para Saxon)
RUN apk add --no-cache openjdk17-jre curl
# Crear directorio de trabajo
WORKDIR /app
# Copiar binario y configuración
COPY --from=builder /app/src/server .
COPY src/app.config .
# Crear carpeta para Saxon y descargarlo
RUN mkdir -p /opt/saxon && \
curl -L -o /opt/saxon/saxon-he.jar https://repo1.maven.org/maven2/net/sf/saxon/Saxon-HE/11.6/Saxon-HE-11.6.jar
# Puerto por defecto (puede ser sobre
+4
View File
@@ -0,0 +1,4 @@
{
"port": "8000",
"saxon_path": "/opt/saxon/saxon-he.jar"
}
+126
View File
@@ -0,0 +1,126 @@
// xslt-playground-backend/main.go
package main
import (
"bytes"
"encoding/json"
"io/ioutil"
"log"
"net/http"
"os"
"os/exec"
"path/filepath"
"time"
"github.com/gin-gonic/gin"
)
type TransformRequest struct {
XSLT string `json:"xslt"`
Version string `json:"version"`
Parameters map[string]string `json:"parameters"`
}
type TransformResponse struct {
Result string `json:"result"`
}
type AppConfig struct {
Port string `json:"port"`
SaxonPath string `json:"saxon_path"`
}
func loadConfig(filename string) (*AppConfig, error) {
data, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
var config AppConfig
if err := json.Unmarshal(data, &config); err != nil {
return nil, err
}
return &config, nil
}
func main() {
config, err := loadConfig("app.config")
if err != nil {
log.Fatalf("failed to load config: %v", err)
}
r := gin.Default()
r.POST("/transform", func(c *gin.Context) {
var req TransformRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
tmpDir, err := ioutil.TempDir("", "xslt")
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "cannot create temp dir"})
return
}
defer os.RemoveAll(tmpDir)
xsltPath := filepath.Join(tmpDir, "transform.xsl")
inputPath := filepath.Join(tmpDir, "input.xml")
outputPath := filepath.Join(tmpDir, "result.xml")
if err := os.WriteFile(xsltPath, []byte(req.XSLT), 0644); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "cannot write xslt"})
return
}
if err := os.WriteFile(inputPath, []byte("<root/>"), 0644); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "cannot write input"})
return
}
cmdArgs := []string{
"-cp", config.SaxonPath,
"net.sf.saxon.Transform",
"-s:" + inputPath,
"-xsl:" + xsltPath,
"-o:" + outputPath,
}
for k, v := range req.Parameters {
cmdArgs = append(cmdArgs, k+"='"+v+"'")
}
cmd := exec.Command("java", cmdArgs...)
var stderr bytes.Buffer
cmd.Stderr = &stderr
timeout := time.Second * 10
errChan := make(chan error, 1)
go func() { errChan <- cmd.Run() }()
select {
case err := <-errChan:
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": stderr.String()})
return
}
case <-time.After(timeout):
cmd.Process.Kill()
c.JSON(http.StatusRequestTimeout, gin.H{"error": "transformation timeout"})
return
}
result, err := os.ReadFile(outputPath)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "cannot read result"})
return
}
c.JSON(http.StatusOK, TransformResponse{Result: string(result)})
})
r.GET("/", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"status": "ok"})
})
r.Run(":" + config.Port)
}