WiP! XSLT actor

This commit is contained in:
Emery Hemingway 2024-02-08 18:13:09 +00:00
parent 1827c91da0
commit 2c61d144d0
11 changed files with 161 additions and 5 deletions

View File

@ -8,3 +8,7 @@ FileSystemUsage = <file-system-usage @path string @size int>.
Pulse = <pulse @periodSec float @proxy #:any>.
XmlTranslation = <xml-translation @xml string @pr any>.
XsltTransform = <xslt-transform @stylesheet string @input string @output string>.
XsltItems = [XsltItem ...].
XsltItem = string.

View File

@ -51,5 +51,9 @@ XmlTranslatorArguments = <xml-translator {
dataspace: #:any
}>.
XsltArguments = <xslt {
dataspace: #:any
}>.
# Reused from syndicate-protocols/transportAddress
Tcp = <tcp @host string @port int>.

View File

@ -1,7 +1,8 @@
{ pkgs ? import <nixpkgs> { } }:
pkgs.buildNimPackage {
name = "dummy";
name = "syndicate_utils";
propagatedNativeBuildInputs = [ pkgs.pkg-config ];
propagatedBuildInputs = [ pkgs.postgresql pkgs.sqlite ];
propagatedBuildInputs = [ pkgs.postgresql pkgs.sqlite pkgs.libxml2 pkgs.libxslt ];
lockFile = ./lock.json;
}

View File

@ -3,10 +3,12 @@ import
preserves
type
XsltItems* = seq[XsltItem]
Pulse* {.preservesRecord: "pulse".} = object
`periodSec`*: float
`proxy`* {.preservesEmbedded.}: Value
XsltItem* = string
XmlTranslation* {.preservesRecord: "xml-translation".} = object
`xml`*: string
`pr`*: Value
@ -15,8 +17,15 @@ type
`path`*: string
`size`*: BiggestInt
proc `$`*(x: Pulse | XmlTranslation | FileSystemUsage): string =
XsltTransform* {.preservesRecord: "xslt-transform".} = object
`stylesheet`*: string
`input`*: string
`output`*: string
proc `$`*(x: XsltItems | Pulse | XsltItem | XmlTranslation | FileSystemUsage |
XsltTransform): string =
`$`(toPreserves(x))
proc encode*(x: Pulse | XmlTranslation | FileSystemUsage): seq[byte] =
proc encode*(x: XsltItems | Pulse | XsltItem | XmlTranslation | FileSystemUsage |
XsltTransform): seq[byte] =
encode(toPreserves(x))

View File

@ -27,6 +27,12 @@ type
JsonSocketTranslatorArguments* {.preservesRecord: "json-socket-translator".} = object
`field0`*: JsonSocketTranslatorArgumentsField0
XsltArgumentsField0* {.preservesDictionary.} = object
`dataspace`* {.preservesEmbedded.}: EmbeddedRef
XsltArguments* {.preservesRecord: "xslt".} = object
`field0`*: XsltArgumentsField0
WebhooksArgumentsField0* {.preservesDictionary.} = object
`endpoints`*: Table[seq[string], EmbeddedRef]
`listen`*: Tcp
@ -84,6 +90,7 @@ type
proc `$`*(x: WebsocketArguments | JsonTranslatorArguments |
JsonTranslatorConnected |
JsonSocketTranslatorArguments |
XsltArguments |
WebhooksArguments |
FileSystemUsageArguments |
SqliteArguments |
@ -98,6 +105,7 @@ proc `$`*(x: WebsocketArguments | JsonTranslatorArguments |
proc encode*(x: WebsocketArguments | JsonTranslatorArguments |
JsonTranslatorConnected |
JsonSocketTranslatorArguments |
XsltArguments |
WebhooksArguments |
FileSystemUsageArguments |
SqliteArguments |

View File

@ -17,7 +17,8 @@ import ./syndesizer/[
pulses,
webhooks,
websockets,
xml_translator]
xml_translator,
xslt_actor]
when withPostgre:
import ./syndesizer/postgre_actor
@ -36,6 +37,7 @@ runActor("syndesizer") do (turn: var Turn; root: Cap):
discard spawnWebhookActor(turn, root)
discard spawnWebsocketActor(turn, root)
discard spawnXmlTranslator(turn, root)
discard spawnXsltActor(turn, root)
when withPostgre:
discard spawnPostgreActor(turn, root)
when withSqlite:

View File

@ -1,2 +1,4 @@
include_rules
: foreach *.nim | $(SYNDICATE_PROTOCOL) ../<schema> |> !nim_check |> | ./<checks>
: xslt_actor.nim | $(SYNDICATE_PROTOCOL) ../<schema> |> !nim |> {bin}
: foreach {bin} |> !assert_built |> ../../tests/built-%b.pr

View File

@ -0,0 +1,70 @@
# SPDX-FileCopyrightText: ☭ Emery Hemingway
# SPDX-License-Identifier: Unlicense
import preserves, syndicate
import ../schema/[assertions, config]
{.passC: staticExec("pkg-config --cflags libxslt").}
{.passL: staticExec("pkg-config --libs libxslt").}
{.pragma: libxslt, header: "libxslt/xslt.h", importc.}
type
xmlDocPtr {.libxslt.} = distinct pointer
xsltStylesheetPtr {.libxslt.} = distinct pointer
proc xmlParseFile(filename: cstring): xmlDocPtr {.libxslt.}
proc xmlFreeDoc(p: xmlDocPtr) {.libxslt.}
proc xsltParseStylesheetFile(filename: cstring): xsltStylesheetPtr {.libxslt.}
proc xsltApplyStylesheet(
style: xsltStylesheetPtr, doc: xmlDocPtr, params: cstringArray): xmlDocPtr {.libxslt.}
proc xsltFreeStylesheet(style: xsltStylesheetPtr) {.libxslt.}
proc xsltSaveResultToString(txt: ptr pointer; len: ptr cint; res: xmlDocPtr; style: xsltStylesheetPtr): cint {.libxslt.}
proc c_free*(p: pointer) {.importc: "free", header: "<stdlib.h>".}
proc xsltSaveResultToString(res: xmlDocPtr; style: xsltStylesheetPtr): string =
var
txt: pointer
len: cint
if xsltSaveResultToString(addr txt, addr len, res, style) < 0:
raise newException(CatchableError, "xsltSaveResultToString failed")
if len > 0:
result = newString(int len)
copyMem(result[0].addr, txt, len)
c_free(txt)
proc initLibXml =
discard
proc spawnXsltActor*(turn: var Turn; root: Cap): Actor {.discardable.} =
spawn("xslt", turn) do (turn: var Turn):
initLibXml()
during(turn, root, ?:XsltArguments) do (ds: Cap):
let sheetsPat = ?Observe(pattern: !XsltTransform) ?? {0: grab(), 1: grab()}
during(turn, ds, sheetsPat) do (stylesheet: Literal[string], input: Literal[string]):
let
cur = xsltParseStylesheetFile(stylesheet.value)
doc = xmlParseFile(input.value)
params = allocCStringArray([])
res = xsltApplyStylesheet(cur, doc, params)
output = xsltSaveResultToString(res, cur)
xmlFreeDoc(res)
xmlFreeDoc(doc)
deallocCStringArray(params)
xsltFreeStylesheet(cur)
publish(turn, ds, XsltTransform(
stylesheet: stylesheet.value,
input: input.value,
output: output,
))
when isMainModule:
import syndicate/relays
runActor("main") do (turn: var Turn; root: Cap):
connectStdio(turn, root)
spawnXsltActor(turn, root)

11
tests/input.xml Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0"?>
<persons>
<person username="JS1">
<name>John</name>
<family-name>Smith</family-name>
</person>
<person username="MI1">
<name>Morka</name>
<family-name>Ismincius</family-name>
</person>
</persons>

26
tests/stylesheet.xslt Normal file
View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" version="1.0">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:template match="/persons">
<html>
<head>
<title>Testing XML Example</title>
</head>
<body>
<h1>Persons</h1>
<ul>
<xsl:apply-templates select="person">
<xsl:sort select="family-name"/>
</xsl:apply-templates>
</ul>
</body>
</html>
</xsl:template>
<xsl:template match="person">
<li>
<xsl:value-of select="family-name"/>
<xsl:text>, </xsl:text>
<xsl:value-of select="name"/>
</li>
</xsl:template>
</xsl:stylesheet>

19
tests/xslt.pr Normal file
View File

@ -0,0 +1,19 @@
<require-service <daemon xslt_actor>>
? <built xslt_actor ?path ?sum> [
<daemon xslt_actor {
argv: [$path]
protocol: application/syndicate
env: { BUILD_SUM: $sum }
}>
]
let ?ds = dataspace
? <service-object <daemon xslt_actor> ?cap> $cap [
<xslt { dataspace: $ds }>
]
$ds [
? <xslt-transform "/home/emery/src/syndicate_utils/tests/stylesheet.xslt" "/home/emery/src/syndicate_utils/tests/input.xml" ?outputs> [
$log ! <log "-" { xslt-outputs: $outputs }>
]
]