mirror of
https://github.com/alexandrev/xslt-lab.git
synced 2026-09-20 04:23:16 +00:00
Initial version
This commit is contained in:
@@ -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
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"port": "8000",
|
||||
"saxon_path": "/opt/saxon/saxon-he.jar"
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user