diff --git a/.circleci/config.yml b/.circleci/config.yml index b436069..8e620b3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,106 +1,112 @@ - -version: 2.1 -executors: - docker-publisher: - environment: - CONTAINER_IMAGE_NAME: proxeus/document-service - docker: - - image: circleci/buildpack-deps:stretch - -jobs: - - build-jar: - docker: - - image: circleci/openjdk:8-jdk - steps: - - checkout - - run: - name: build Jar file "document-service.jar" - command: make build - - persist_to_workspace: - root: . - paths: - - ./document-service.jar - - build-docker: - executor: docker-publisher - steps: - - checkout - - attach_workspace: - at: ~/project/ - - setup_remote_docker - - run: - name: Build Docker image - command: | - docker build -f Dockerfile.dev -t $CONTAINER_IMAGE_NAME:latest -t $CONTAINER_IMAGE_NAME . - - run: - name: Archive Docker image - command: docker save -o image.tar $CONTAINER_IMAGE_NAME - - persist_to_workspace: - root: . - paths: - - image.tar - - publish-latest: - executor: docker-publisher - steps: - - attach_workspace: - at: /tmp/workspace - - setup_remote_docker - - run: - name: Load archived Docker image - command: docker load -i /tmp/workspace/image.tar - - run: - name: Publish Docker Image to Docker Hub - command: | - echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin - docker push $CONTAINER_IMAGE_NAME - - publish-staging: - executor: docker-publisher - steps: - - attach_workspace: - at: /tmp/workspace - - setup_remote_docker - - run: - name: Load archived Docker image - command: docker load -i /tmp/workspace/image.tar - - run: - name: Tag docker image - command: docker tag $CONTAINER_IMAGE_NAME $CONTAINER_IMAGE_NAME:staging - - run: - name: Publish Docker Image to Docker Hub - command: | - echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin - docker push $CONTAINER_IMAGE_NAME:staging - -workflows: - version: 2 - build-master: - jobs: - - build-jar -# filters: -# branches: -# only: master - - build-docker: - requires: - - build-jar -# filters: -# branches: -# only: master - - publish-latest: - requires: - - build-docker -# filters: -# branches: -# only: master - - hold: - type: approval - requires: - - build-docker - - publish-staging: - requires: - - hold -# filters: -# branches: -# only: master \ No newline at end of file +--- +version: 2.1 +executors: + docker-publisher: + environment: + CONTAINER_IMAGE_NAME: proxeus/document-service + docker: + - image: circleci/buildpack-deps:stretch + +jobs: + build-jar: + docker: + - image: circleci/openjdk:8-jdk + steps: + - checkout + - run: + name: build Jar file "document-service.jar" + command: make build + - persist_to_workspace: + root: . + paths: + - ./document-service.jar + + build-docker: + executor: docker-publisher + steps: + - checkout + - attach_workspace: + at: ~/project/ + - setup_remote_docker + - run: + name: Build Docker image + command: | + docker build -f Dockerfile.dev -t $CONTAINER_IMAGE_NAME -t $CONTAINER_IMAGE_NAME . + - run: + name: Archive Docker image + command: docker save -o image.tar $CONTAINER_IMAGE_NAME + - persist_to_workspace: + root: . + paths: + - image.tar + + publish-staging: + executor: docker-publisher + steps: + - attach_workspace: + at: /tmp/workspace + - setup_remote_docker + - run: + name: Load archived Docker image + command: docker load -i /tmp/workspace/image.tar + - run: + name: Tag staging docker image + command: docker tag $CONTAINER_IMAGE_NAME $CONTAINER_IMAGE_NAME:staging + - run: + name: Publish Docker Image to Docker Hub + command: | + echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin + docker push $CONTAINER_IMAGE_NAME:staging + + publish-latest: + executor: docker-publisher + steps: + - attach_workspace: + at: /tmp/workspace + - setup_remote_docker + - run: + name: Load archived Docker image + command: docker load -i /tmp/workspace/image.tar + - run: + name: Tag latest docker image + command: docker tag $CONTAINER_IMAGE_NAME $CONTAINER_IMAGE_NAME:latest + - run: + name: Publish Docker Image to Docker Hub + command: | + echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin + docker push $CONTAINER_IMAGE_NAME:latest + +workflows: + version: 2.1 + build-master: + jobs: + - build-jar + - build-docker: + requires: + - build-jar + filters: + branches: + only: master + - approve-staging: + type: approval + requires: + - build-docker + filters: + branches: + only: master + - publish-staging: + requires: + - approve-staging + - approve-latest: + type: approval + requires: + - publish-staging + filters: + branches: + only: master + - publish-latest: + requires: + - approve-latest + filters: + branches: + only: master diff --git a/.gitignore b/.gitignore index 671c2a7..5d28ce1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,15 @@ /build/ /.idea/ /logs/ +out/ +/data + document-service.jar +**/.DS_Store +.classpath +.project +.settings/ +bin/ # Ignore Gradle GUI config gradle-app.setting @@ -12,5 +20,3 @@ gradle-app.setting # Cache of project .gradletasknamecache - -.DS_Store diff --git a/Dockerfile b/Dockerfile index 4bb7f72..f33a456 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,25 +1,26 @@ -FROM eu.gcr.io/blockfactory-01/document-service-base +FROM gradle:jdk8 as build -#font configuration -COPY ./00-fontconfig.conf /etc/fonts/conf.d/ - -RUN mkdir /document-service /document-service/fonts /document-service/logs - -COPY ./document-service.jar /document-service/ -#COPY ./config.json /document-service/ -COPY ./ui_service /document-service/ -COPY ./run /document-service/ - -RUN chmod +x /document-service/ui_service -RUN chmod +x /document-service/run +COPY --chown=gradle:gradle . /home/gradle/project/ +WORKDIR /home/gradle/project +RUN gradle clean test buildJar --no-daemon +FROM ubuntu:18.04 +EXPOSE 2115 ENV LANG="en_US.UTF-8" -WORKDIR /document-service +## Fix installation of openjdk-8-jre-headless (https://github.com/nextcloud/docker/issues/380) +RUN mkdir -p /usr/share/man/man1 +RUN apt-get update && apt-get install -y \ + software-properties-common \ + language-pack-en-base \ + openjdk-8-jre-headless \ + libreoffice \ + && apt-get clean && rm -rf /var/cache/* /var/lib/apt/lists/* -#document-service -EXPOSE 2115 -#UI -EXPOSE 58082 +#font configuration +COPY ./00-fontconfig.conf /etc/fonts/conf.d/ + +RUN mkdir /document-service /document-service/fonts /document-service/logs +COPY --from=build /home/gradle/project/document-service.jar /document-service/ -CMD ["./run"] +CMD ["/usr/bin/java", "-jar", "/document-service/document-service.jar"] diff --git a/Dockerfile.dev b/Dockerfile.dev deleted file mode 100644 index 2245232..0000000 --- a/Dockerfile.dev +++ /dev/null @@ -1,34 +0,0 @@ -FROM ubuntu:18.04 - -## Fix installation of openjdk-8-jre-headless (https://github.com/nextcloud/docker/issues/380) -RUN mkdir -p /usr/share/man/man1 -RUN apt-get update && apt-get install -y \ - software-properties-common \ - language-pack-en-base \ - openjdk-8-jre-headless \ - libreoffice \ - && apt-get clean && rm -rf /var/cache/* /var/lib/apt/lists/* - -#font configuration -COPY ./00-fontconfig.conf /etc/fonts/conf.d/ - -RUN mkdir /document-service /document-service/fonts /document-service/logs - -COPY ./document-service.jar /document-service/ -#COPY ./config.json /document-service/ -COPY ./ui_service /document-service/ -COPY ./run /document-service/ - -RUN chmod +x /document-service/ui_service -RUN chmod +x /document-service/run - -ENV LANG="en_US.UTF-8" - -WORKDIR /document-service - -#document-service -EXPOSE 2115 -#UI -EXPOSE 58082 - -CMD ["./run"] diff --git a/Makefile b/Makefile index 7cdfee4..2e9c116 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,12 @@ -.PHONY: all build build-docker clean clean-docker +.PHONY: all build build-docker clean -all: build build-docker run-docker +all: build build-docker build: - gradle buildJar + gradle test buildJar + build-docker: - docker image build -f Dockerfile.dev -t document-service . + docker image build -t document-service . + clean: rm -rf .gradle build document-service.jar -clean-docker: - ./rmalldockers.sh diff --git a/README.md b/README.md index 581ad79..73cdb25 100644 --- a/README.md +++ b/README.md @@ -21,60 +21,53 @@ Currently supported template format is `ODT`. Other formats like `DOCX` are not + gradle + docker -#### Building for development +#### Building +``` +sudo docker build -t document-service . ``` - gradle buildJar - sudo docker image build -f Dockerfile.dev -t document-service . - - #run 2115 for the document-service and 58082 for the UI in case it is needed - sudo docker run -p 2115:2115 -p 58082:58082 document-service - - #single cmd - gradle buildJar && sudo docker image build -t document-service -f ./Dockerfile.dev . && sudo docker run -p 2115:2115 -p 58082:58082 document-service - #for removing all dockers you can run - sudo ./rmalldockers.sh +#### Local run for development +``` + sudo docker run -p 2115:2115 document-service ``` -To run a development environment use this repository: https://git.proxeus.com/docker/proxeus-platform -#### Building for production +#### Use the official docker hub image from Proxeus ``` -gradle buildJar -sudo docker image build -t document-service -f ./Dockerfile . +sudo docker run -p 2115:2115 proxeus/document-service:latest ``` ## Commandline client -``` -#compile usage: -./dsclient -t tmpl.odt -o my.pdf -./dsclient -u http://123.12.12.111:8888 -f pdf -t my/tmpl.odt -d data.json -a myImage.png -a my/images/dir -o output.pdf -#print vars usage: -./dsclient -m vars -t my/tmpl.odt -p input. - - -a value - asset files, provide directory or file like -a file1 -a file2 -a dir1 - -d string - JSON file path - -e embed compilation error into the returned document - -f string - result format, possible values: pdf, odt, docx or doc (default "pdf") - -m string - compile or vars (default "compile") - -o string - output path, extension will be attached if not provided (default "result") - -p string - var prefix to filter vars - -t string - ODT template path - -u string - Document-Service URL (default "http://localhost:2115") +You can simply interact with the server using `curl`. + ``` +# To compile a template to pdf (pdf is the default) + +curl --form template=@template.odt --form data=@data.json http:///compile > result.pdf + +# To compile a template to odt (available format are pdf, odt, docx or doc) + +curl --form template=@template.odt --form data=@data.json http:///compile?format=odt > result.pdf -## Playground UI -If you want to get familiar with the Document-Service, you should start the docker with `-p 58082:58082` to expose the UI. -The UI provides access to the API, documentation and examples. You can play around with all available methods. -It is recommended to disable the UI under production. +# To embed the template rendering error in the pdf result (add the `error` query parameter + +curl --form template=@template.odt --form data=@data.json http:///compile?error > result.pdf + +# To get the variables used in a template + +curl --data-binary @template.odt http:///vars +curl --form template=@template.odt http://vars + +# To get the subset of the variable starting with a given prefix + +curl --data-binary @template.odt http:///vars?prefix=foo +curl --form template=@template.odt http://vars?prefix=bar + +# To add asset files + +curl --form template=@template.odt --form data=@data.json --form asset1=@asset1.png http:///compile > result.pdf + +``` ## API The API documentation can be accessed by `:/api` or over the playground UI on the top right corner. diff --git a/build.gradle b/build.gradle index 78b31f4..0912c84 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,8 @@ +/* plugins { - id "com.github.hierynomus.license" version "0.15.0" + id "com.github.hierynomus.license" version "0.15.0j" } +*/ apply plugin: 'groovy' apply plugin: 'java' @@ -9,6 +11,7 @@ version = '1.0' sourceCompatibility = 1.8 targetCompatibility = 1.8 + allprojects { gradle.projectsEvaluated { tasks.withType(JavaCompile) { @@ -65,7 +68,7 @@ dependencies { compile "javax.xml.bind:jaxb-api:2.2.11", ex compile "commons-io:commons-io:RELEASE", ex compile "javaxt:javaxt-core:1.7.8", ex - compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.8.1' + compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.9' compile "commons-codec:commons-codec:1.11", ex compile "commons-io:commons-io:2.5", ex @@ -80,5 +83,6 @@ dependencies { compile "org.libreoffice:juh:6.2.3", ex compile "org.libreoffice:ridl:6.2.3", ex - testCompile "junit:junit:4.10" + testCompile "junit:junit:4.13" + testCompile "org.mockito:mockito-core:2.+" } diff --git a/client/cmd/bin/dsclient b/client/cmd/bin/dsclient deleted file mode 100644 index c5531f5..0000000 Binary files a/client/cmd/bin/dsclient and /dev/null differ diff --git a/client/cmd/bin/dsclient.exe b/client/cmd/bin/dsclient.exe deleted file mode 100644 index be2bad3..0000000 Binary files a/client/cmd/bin/dsclient.exe and /dev/null differ diff --git a/client/cmd/bin/dsclient.mac b/client/cmd/bin/dsclient.mac deleted file mode 100644 index 2f69809..0000000 Binary files a/client/cmd/bin/dsclient.mac and /dev/null differ diff --git a/client/cmd/main.go b/client/cmd/main.go deleted file mode 100644 index 9e1d624..0000000 --- a/client/cmd/main.go +++ /dev/null @@ -1,138 +0,0 @@ -package main - -import ( - "encoding/json" - "flag" - "fmt" - "git.proxeus.com/ui/doctmpl" - "github.com/prometheus/common/log" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" -) - -type arrayFlags []string - -func (i *arrayFlags) String() string { - return "asset files list" -} - -func (i *arrayFlags) Set(value string) error { - *i = append(*i, value) - return nil -} - -var assetFiles arrayFlags - -func main() { - var url = flag.String("u", "http://localhost:2115", "Document-Service URL") - method := flag.String("m", "compile", "compile or vars") - tmplPath := flag.String("t", "", "ODT template path") - format := flag.String("f", "pdf", "result format, possible values: pdf, odt, docx or doc") - dataPath := flag.String("d", "", "JSON file path") - embedError := flag.Bool("e", false, "embed compilation error into the returned document") - flag.Var(&assetFiles, "a", "asset files, provide directory or file like -a file1 -a file2 -a dir1") - varPrefix := flag.String("p", "", "var prefix to filter vars") - outPath := flag.String("o", "result", "output path, extension will be attached if not provided") - flag.Usage = func() { - fmt.Fprintf(os.Stderr, "Usage of %s:\ncompile usage:\n%s -t tmpl.odt -o my.pdf\n%s -u http://123.12.12.111:8888 -f pdf -t my/tmpl.odt -d data.json -a myImage.png -a my/images/dir -o output.pdf \nprint vars usage:\n%s -m vars -t my/tmpl.odt -p input.\n\n", os.Args[0], os.Args[0], os.Args[0], os.Args[0]) - flag.PrintDefaults() - } - flag.Parse() - if *tmplPath == "" { - fmt.Println("template path must be provided, please use -t") - fmt.Println() - flag.Usage() - os.Exit(1) - } - ds := &doctmpl.DocumentServiceClient{Url: *url} - if *method == "compile" { - form := doctmpl.Format(*format) - r, err := ds.Compile(doctmpl.Template{ - Format: form, - Data: provideData(*dataPath), - TemplatePath: *tmplPath, - Assets: getFilesListOnly(assetFiles), - EmbedError: *embedError, - }) - if err != nil { - log.Error(err) - os.Exit(1) - } - out := *outPath - if !strings.Contains(filepath.Base(out), ".") { - out = "." + form.String() - } - outFile, err := os.OpenFile(out, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) - if err != nil { - log.Error(err) - os.Exit(1) - } - defer r.Body.Close() - defer outFile.Close() - _, err = io.Copy(outFile, r.Body) - if err != nil { - log.Error(err) - os.Exit(1) - } - } else if *method == "vars" { - v, err := ds.Vars(*tmplPath, *varPrefix) - if err != nil { - log.Error(err) - os.Exit(1) - } - fmt.Println(v) - } -} - -func provideData(jf string) interface{} { - d := map[string]interface{}{} - f, err := os.Open(jf) - if err != nil { - return d - } - defer f.Close() - bts, err := ioutil.ReadAll(f) - if err != nil { - return d - } - err = json.Unmarshal(bts, d) - if err != nil { - return d - } - return d -} - -//serializes directories to file entries -func getFilesListOnly(files []string) []string { - serializedFiles := make([]string, 0) - for _, a := range files { - rec(&serializedFiles, a) - } - fmt.Println(serializedFiles) - return serializedFiles -} - -func rec(i *[]string, name string) { - fi, err := os.Stat(name) - if err != nil { - fmt.Println(err) - panic(err) - return - } - switch mode := fi.Mode(); { - case mode.IsDir(): - files, err := ioutil.ReadDir(name) - if err != nil { - fmt.Println(err) - panic(err) - } - for _, f := range files { - rec(i, filepath.Join(name, f.Name())) - } - case mode.IsRegular(): - *i = append(*i, name) - } -} diff --git a/client/document_service_client.go b/client/document_service_client.go deleted file mode 100644 index 6dd1f68..0000000 --- a/client/document_service_client.go +++ /dev/null @@ -1,365 +0,0 @@ -package dsclient - -import ( - "archive/zip" - "compress/gzip" - "encoding/json" - "errors" - "io" - "io/ioutil" - "net/http" - "net/url" - "os" - "path" - "time" -) - -type ( - Format string - OSArchType string - DocumentServiceClient struct{ Url string } -) - -const ( - PDF Format = "pdf" - ODT Format = "odt" - DOCX Format = "docx" - DOC Format = "doc" - - Linux OSArchType = "linux_x86_64" - Win64 OSArchType = "win_x86_64" - Win32 OSArchType = "win_x86" - Darwin OSArchType = "mac_x86_64" -) - -type Template struct { - Format Format //the result format, default PDF - Data interface{} //the data the template is going to resolved with - TemplatePath string //odt template - Assets []string //assets that are referenced in Data and you want to include into the ZIP - EmbedError bool //print compilation error in the document -} - -//Compile packs the provided files into a ZIP and sends it to the document-service to be compiled as the format you have provided. -//if format is empty, it will take the default one which is PDF. -func (ds *DocumentServiceClient) Compile(template Template) (resp *http.Response, err error) { - var odtTmplFile *os.File - odtTmplFile, err = os.Open(template.TemplatePath) - if err != nil { - return - } - fstat, er := odtTmplFile.Stat() - if er != nil { - err = er - return - } - requestReader, requestWriter := io.Pipe() - go func() { - zipWriter := zip.NewWriter(requestWriter) - defer func() { - if zipWriter != nil && zipWriter.Close() != nil { - requestWriter.Close() - return - } - if odtTmplFile != nil { - odtTmplFile.Close() - } - if requestWriter != nil { - requestWriter.Close() - } - }() - header, err := zip.FileInfoHeader(fstat) - if err != nil { - return - } - header.Name = "tmpl.odt" - - // Change to deflate to gain better compression - // see http://golang.org/pkg/archive/zip/#pkg-constants - header.Method = zip.Deflate - odtZipWriter, err := zipWriter.CreateHeader(header) - if err != nil { - return - } - _, err = io.CopyN(odtZipWriter, odtTmplFile, fstat.Size()) - if err != nil { - return - } - - //insert data as a json file in the ZIP - jsonBytes, err := json.Marshal(template.Data) - if err != nil { - jsonBytes = []byte("{}") - } - - djh := &zip.FileHeader{ - Name: "data.json", - Method: zip.Deflate, - } - - dataJsonWriter, err := zipWriter.CreateHeader(djh) - if err != nil { - return - } - _, err = dataJsonWriter.Write(jsonBytes) - if err != nil { - return - } - //insert assets - if len(template.Assets) > 0 { - assetToZIPWriter := func(assetPath string, zipWriter *zip.Writer) { - assetFile, err := os.Open(assetPath) - if err != nil { - return - } - defer assetFile.Close() - assetStat, err := assetFile.Stat() - if err != nil { - return - } - - assetHeader, err := zip.FileInfoHeader(assetStat) - if err != nil { - return - } - - // Change to deflate to gain better compression - // see http://golang.org/pkg/archive/zip/#pkg-constants - assetHeader.Method = zip.Deflate - assetWriter, err := zipWriter.CreateHeader(assetHeader) - if err != nil { - return - } - _, err = io.CopyN(assetWriter, assetFile, assetStat.Size()) - if err != nil { - return - } - } - for _, assetPath := range template.Assets { - assetToZIPWriter(assetPath, zipWriter) - } - } - }() - req, er := http.NewRequest("POST", ds.makeUrl("compile"), requestReader) - if er != nil { - err = er - return - } - if template.Format != "" { - q := req.URL.Query() - q.Add("format", template.Format.String()) - req.URL.RawQuery = q.Encode() - } - if template.EmbedError { - q := req.URL.Query() - //just need to provide the parameter - //no value needed - q.Add("error", "1") - req.URL.RawQuery = q.Encode() - } - req.Header.Set("Connection", "Keep-Alive") - req.Header.Set("Cache-Control", "no-cache") - req.Header.Set("Content-Type", "application/zip") - - client := &http.Client{} - client.Timeout = time.Duration(time.Second * 20) - resp, err = client.Do(req) - if err != nil { - return - } - err = checkGzip(resp) - if err != nil { - return - } - if resp.StatusCode != 200 { - var b []byte - defer resp.Body.Close() - b, err = ioutil.ReadAll(resp.Body) - if err != nil { - return - } - err = errors.New(string(b)) - } - return -} - -//Vars returns a list of the vars contained in the provided template. -//You can filter them with the prefix if needed. -func (ds *DocumentServiceClient) Vars(tmplPath, prefix string) ([]string, error) { - odtTmplFile, err := os.Open(tmplPath) - if err != nil { - return nil, err - } - fstat, err := odtTmplFile.Stat() - if err != nil { - return nil, err - } - requestReader, requestWriter := io.Pipe() - go func() { - defer func() { - if odtTmplFile != nil { - _ = odtTmplFile.Close() - } - if requestWriter != nil { - _ = requestWriter.Close() - } - }() - _, err = io.CopyN(requestWriter, odtTmplFile, fstat.Size()) - if err != nil { - return - } - }() - req, er := http.NewRequest("POST", ds.makeUrl("vars"), requestReader) - if er != nil { - return nil, er - } - if prefix != "" { - q := req.URL.Query() - q.Add("prefix", prefix) - req.URL.RawQuery = q.Encode() - } - req.Header.Set("Connection", "Keep-Alive") - req.Header.Set("Cache-Control", "no-cache") - req.Header.Set("Content-Type", "application/zip") - - client := &http.Client{} - client.Timeout = time.Duration(time.Second * 20) - resp, er := client.Do(req) - if er != nil { - return nil, er - } - err = checkGzip(resp) - if err != nil { - return nil, err - } - if resp.StatusCode == http.StatusOK { - defer resp.Body.Close() - bts, er := ioutil.ReadAll(resp.Body) - if er != nil { - return nil, er - } - var vars []string - err = json.Unmarshal(bts, &vars) - if err != nil { - return nil, err - } - return vars, nil - } else { - var b []byte - defer resp.Body.Close() - b, err = ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - err = errors.New(string(b)) - return nil, err - } -} - -//Download the template assistance extension for your writer. -func (ds *DocumentServiceClient) DownloadExtension(arch string) (resp *http.Response, err error) { - req, err := http.NewRequest("GET", ds.makeUrl("extension"), nil) - if err != nil { - return nil, err - } - - q := req.URL.Query() - q.Add("os", OSArchType(arch).String()) - req.URL.RawQuery = q.Encode() - - client := &http.Client{} - client.Timeout = time.Duration(time.Second * 10) - resp, err = client.Do(req) - if err != nil { - return - } - if resp.StatusCode != 200 { - err = os.ErrInvalid - return - } - err = checkGzip(resp) - if err != nil { - return - } - return -} - -//Download the how it works document. -func (ds *DocumentServiceClient) DownloadHowItWorksPDF(writer io.Writer) error { - return ds.downloadPDF("how-it-works", false, writer) -} - -//Download the example document. -func (ds *DocumentServiceClient) DownloadExamplePDF(raw bool, writer io.Writer) error { - return ds.downloadPDF("example", raw, writer) -} - -func (ds *DocumentServiceClient) downloadPDF(method string, raw bool, writer io.Writer) error { - rp := "" - if raw { - rp = "?raw" - } - req, err := http.NewRequest("GET", ds.makeUrl(method)+rp, nil) - if err != nil { - return err - } - client := &http.Client{} - client.Timeout = time.Duration(time.Second * 10) - resp, err := client.Do(req) - if err != nil { - return err - } - if resp.StatusCode != 200 { - return os.ErrInvalid - } - err = checkGzip(resp) - if err != nil { - return err - } - _, err = io.Copy(writer, resp.Body) - resp.Body.Close() - return err -} - -func checkGzip(resp *http.Response) (err error) { - switch resp.Header.Get("Content-Encoding") { - case "gzip": - resp.Body, err = gzip.NewReader(resp.Body) - } - return -} - -func (ds *DocumentServiceClient) makeUrl(method string) string { - u, err := url.Parse(ds.Url) - if err != nil { - return "" - } - u.Path = path.Join(u.Path, method) - return u.String() -} - -func (f Format) String() string { - switch f { - case ODT: - return string(ODT) - case DOCX: - return string(DOCX) - case DOC: - return string(DOC) - default: - return string(PDF) - } -} - -func (f OSArchType) String() string { - switch f { - case Win64: - return string(Win64) - case Win32: - return string(Win32) - case Darwin: - return string(Darwin) - default: - return string(Linux) - } -} diff --git a/conf.json b/conf.json new file mode 100644 index 0000000..c669a8e --- /dev/null +++ b/conf.json @@ -0,0 +1,24 @@ +{ + "protocol":"http", + "host":"0.0.0.0", + "port":2115, + "tmpFolder":"docsCache",/** cache during a request, it will be deleted when the request is finished **/ + "min": 10,/** min workers **/ + "max": 100,/** max workers **/ + "timeout":"30s",/** timeout duration **/ + "logConfig":{ + "level":"TRACE", /** OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL **/ + "level_console":"DEBUG", /** OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL **/ + "maxFileSize": "5MB", + "maxBackupIndex": 5, + "pattern": "%d{dd.MM.yyyy HH:mm:ss} %-5p %c{1}:%L - %m%n", + "filePath":"./logs/document-service.log" + }, + "libreConfig":{ + "librepath":"/Applications/LibreOffice.app/Contents/MacOS/soffice", /** the libreoffice executable folder path **/ + "min" : 10, /** default 8 | min executables ready to be ready. An executable is mainly needed to convert to PDF. It is recommended to use one exe for a request at the time.**/ + "max" : 100, /** default 40 | max capacity of executable running. The next request will be on hold until one is freed or until request timeout..**/ + "highLoad": 55 /** highLoad defines the percentage of executables in use, when it is reached prepare new ones to be ready for high availability and fast response.**/ + /** Please note! LibreOffice likes to fail sometimes, to have a stable failover, you might want to keep the highLoad value around 50% or even lower.**/ + } +} \ No newline at end of file diff --git a/doc/dependency_decisions.yml b/doc/dependency_decisions.yml index 710984b..1746e6d 100644 --- a/doc/dependency_decisions.yml +++ b/doc/dependency_decisions.yml @@ -23,3 +23,57 @@ :why: :versions: [] :when: 2020-02-06 00:11:53.383908000 Z +- - :permit + - MIT + - :who: + :why: + :versions: [] + :when: 2019-12-20 09:25:04.086031000 Z +- - :permit + - Apache 2.0 + - :who: + :why: + :versions: [] + :when: 2019-12-20 09:25:50.159396000 Z +- - :permit + - Apache 2.0, Eclipse Public License - Version 1.0 + - :who: + :why: + :versions: [] + :when: 2019-12-20 09:26:16.280768000 Z +- - :approve + - juh + - :who: + :why: LibreOffice MPL 2.0 + :versions: [] + :when: 2019-12-20 13:55:54.070224000 Z +- - :approve + - jurt + - :who: + :why: LibreOffice MPL 2.0 + :versions: [] + :when: 2019-12-20 13:55:58.446785000 Z +- - :approve + - ridl + - :who: + :why: LibreOffice MPL 2.0 + :versions: [] + :when: 2019-12-20 13:56:05.186925000 Z +- - :approve + - unoil + - :who: + :why: LibreOffice MPL 2.0 + :versions: [] + :when: 2019-12-20 13:56:10.946673000 Z +- - :approve + - javax.servlet-api + - :who: + :why: GPLv2 with CPE + :versions: [] + :when: 2019-12-20 13:56:57.264730000 Z +- - :approve + - jaxb-api + - :who: + :why: GPLv2 with CPE + :versions: [] + :when: 2019-12-20 14:04:55.702653000 Z diff --git a/docker-compose.override.yml b/docker-compose.override.yml new file mode 100644 index 0000000..e25a508 --- /dev/null +++ b/docker-compose.override.yml @@ -0,0 +1,7 @@ +--- +version: '3.7' + +services: + document-service: + build: + context: . diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..316e8dd --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,23 @@ +--- +version: '3.7' + +networks: + xes-platform-network: + name: xes-platform-network + +services: + document-service: + image: proxeus/document-service:latest + container_name: xes_document_service + networks: + - xes-platform-network + restart: unless-stopped + environment: + TZ: Europe/Zurich + ports: + - "2115:2115" + - "58082:58082" + volumes: + - ${PROXEUS_DATA_DIR:-./data}/document-service/logs:/document-service/logs + - ${PROXEUS_DATA_DIR:-./data}/document-service/fonts:/document-service/fonts + - ${PROXEUS_DATA_DIR:-./data}/document-service/tmp:/tmp diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index ca78035..758de96 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f4e530c..3e210e9 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Jan 18 21:59:36 CET 2019 +#Mon Mar 02 14:33:08 CET 2020 +distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-all.zip +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 27309d9..cccdd3d 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -33,11 +33,11 @@ DEFAULT_JVM_OPTS="" # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -154,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 832fdb6..e95643d 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,90 +1,84 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/output.pdf b/output.pdf new file mode 100644 index 0000000..ad4ee2f Binary files /dev/null and b/output.pdf differ diff --git a/rmalldockers.sh b/rmalldockers.sh deleted file mode 100644 index c05da7c..0000000 --- a/rmalldockers.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -# Delete all containers -docker rm $(docker ps -a -q) -# Delete all images -docker rmi $(docker images -q) \ No newline at end of file diff --git a/src/main/java/com/proxeus/Application.java b/src/main/java/com/proxeus/Application.java index 55d3a46..c3b3b5d 100644 --- a/src/main/java/com/proxeus/Application.java +++ b/src/main/java/com/proxeus/Application.java @@ -1,20 +1,14 @@ package com.proxeus; import com.proxeus.util.Json; - import org.apache.commons.io.FileUtils; -import org.apache.log4j.ConsoleAppender; -import org.apache.log4j.Level; -import org.apache.log4j.Logger; -import org.apache.log4j.PatternLayout; -import org.apache.log4j.RollingFileAppender; +import org.apache.log4j.*; +import spark.utils.IOUtils; import java.io.File; import java.io.FileInputStream; import java.util.Map; -import spark.utils.IOUtils; - /** * Application is the config and log init helper. */ diff --git a/src/main/java/com/proxeus/Config.java b/src/main/java/com/proxeus/Config.java index 6d0d7ff..b98824d 100644 --- a/src/main/java/com/proxeus/Config.java +++ b/src/main/java/com/proxeus/Config.java @@ -11,22 +11,22 @@ * Server config */ public class Config { - public String protocol = "http"; - public String host = "localhost"; - public Integer port = 2115; - public String tmpFolder = "docsCache"; - public String timeout = "10s"; + private String protocol = "http"; + private String host = "localhost"; + private Integer port = 2115; + private String tmpFolder = "docsCache"; + private String timeout = "10s"; //workers - public int min = 8; - public int max = 100; - public int timeoutMillis = 100000; + private int min = 8; + private int max = 100; + private int timeoutMillis = 100000; private static Map config; public Config(){} - public static Config create(Map params){ + public static Config create(Map params) { config = params; Config conf = root(Config.class); System.setProperty("document.template.cache", conf.tmpFolder); @@ -56,7 +56,20 @@ public static long parseDurationToMillis(String duration) { return TimeUnit.DAYS.toMillis(dur); } } - return 0; + + throw new RuntimeException("parsing " + duration + ". Please provide duration in the following format: '3s'"); + } + + public int getTimeoutMillis() { + return timeoutMillis; + } + + public int getMin() { + return min; + } + + public int getMax() { + return max; } public String getProtocol() { @@ -76,25 +89,6 @@ public String toString(){ return Json.toJson(config); } - @SuppressWarnings("unchecked") - public static Map getConfigOf(String module){ - try{ - return (Map)config.get(module); - }catch(Exception e){ - e.printStackTrace(); - } - return null; - } - - public static T fromJson(byte[] json, Class clazz){ - try { - - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - public static T by(Class clazz){ T o = map(config, clazz); if(o == null){ diff --git a/src/main/java/com/proxeus/SparkServer.java b/src/main/java/com/proxeus/SparkServer.java index 9e2efa0..0d2dcb7 100644 --- a/src/main/java/com/proxeus/SparkServer.java +++ b/src/main/java/com/proxeus/SparkServer.java @@ -1,7 +1,9 @@ package com.proxeus; import com.proxeus.document.FileResult; +import com.proxeus.document.Template; import com.proxeus.document.TemplateCompiler; +import com.proxeus.document.TemplateFormatter; import com.proxeus.error.BadRequestException; import com.proxeus.error.CompilationException; import com.proxeus.error.NotImplementedException; @@ -12,56 +14,57 @@ import com.proxeus.office.libre.exe.LibreOfficeFormat; import com.proxeus.util.Json; import com.proxeus.util.zip.Zip; - +import com.proxeus.xml.template.TemplateHandlerFactory; +import com.proxeus.xml.template.TemplateVarParserFactory; +import com.proxeus.xml.template.jtwig.JTwigTemplateHandlerFactory; +import com.proxeus.xml.template.jtwig.JTwigTemplateVarParserFactory; import org.apache.commons.fileupload.MultipartStream; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.time.StopWatch; import org.apache.log4j.Logger; import org.eclipse.jetty.io.EofException; +import spark.Response; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; +import javax.servlet.MultipartConfigElement; +import java.io.*; import java.net.HttpURLConnection; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.StandardCopyOption; +import java.util.Set; import java.util.concurrent.TimeUnit; -import spark.Response; - import static com.proxeus.Application.config; -import static spark.Spark.get; -import static spark.Spark.ipAddress; -import static spark.Spark.port; -import static spark.Spark.post; -import static spark.Spark.staticFiles; -import static spark.Spark.threadPool; +import static org.apache.commons.fileupload.FileUploadBase.CONTENT_DISPOSITION; +import static org.apache.commons.fileupload.FileUploadBase.MULTIPART_FORM_DATA; +import static spark.Spark.*; /** * SparkServer defines the protocol of this services. */ public class SparkServer { - private LibreOfficeAssistant libreOfficeAssistant; + private TemplateFormatter templateFormatter; + private TemplateHandlerFactory templateHandlerFactory; + private TemplateVarParserFactory templateVarParserFactory; private TemplateCompiler templateCompiler; private final Charset defaultCharset = StandardCharsets.UTF_8; private final String JSON_CONTENT_TYPE = "application/json; charset=UTF-8"; private final String TEXT_CONTENT_TYPE = "text/plain; charset=UTF-8"; - public SparkServer(Config config) { + SparkServer(Config config) { removeTheDiskCacheOfDocs(); Logger log = Logger.getLogger(this.getClass()); - threadPool(config.max, config.min, config.timeoutMillis); + threadPool(config.getMax(), config.getMin(), config.getTimeoutMillis()); port(config.getPort()); ipAddress(config.getHost()); try { - libreOfficeAssistant = new LibreOfficeAssistant(Config.by(LibreConfig.class)); - templateCompiler = new TemplateCompiler(config.getTmpFolder(), libreOfficeAssistant); + templateFormatter = new LibreOfficeAssistant(Config.by(LibreConfig.class)); + templateHandlerFactory = new JTwigTemplateHandlerFactory(); + templateVarParserFactory = new JTwigTemplateVarParserFactory(); + templateCompiler = new TemplateCompiler(config.getTmpFolder(), templateFormatter, templateHandlerFactory, templateVarParserFactory); } catch (Exception e) { e.printStackTrace(); System.exit(1); @@ -76,40 +79,49 @@ public SparkServer(Config config) { return 0; }); get("/how-it-works", (request, response) -> { - try{ + try { boolean inline = request.queryMap().hasKey("inline"); - response.raw().setContentType(LibreOfficeFormat.PDF.contentType); - response.raw().setHeader("Content-Disposition", (inline?"inline":"attachment")+"; filename=\"how.it.works.pdf\""); + response.raw().setContentType(LibreOfficeFormat.PDF.getContentType()); + response.raw().setHeader(CONTENT_DISPOSITION, (inline ? "inline" : "attachment") + "; filename=\"how.it.works.pdf\""); streamAndClose(getODTAsPDFFromResources(config, "how.it.works.odt"), response.raw().getOutputStream()); - }catch (Exception e){ + } catch (Exception e) { notFound(response); } return 0; }); get("/example", (request, response) -> { - try{ + try { InputStream is; LibreOfficeFormat format; - if(request.queryMap().hasKey("raw")){ + if (request.queryMap().hasKey("raw")) { format = LibreOfficeFormat.ODT; is = SparkServer.class.getResourceAsStream("/example/tmpl.odt"); - }else{ + } else { format = LibreOfficeFormat.PDF; is = getDirAsPDFFromResources(config, "example"); } boolean inline = request.queryMap().hasKey("inline"); - response.raw().setContentType(format.contentType); - response.raw().setHeader("Content-Disposition", (inline?"inline":"attachment")+"; filename=\"example."+format.ext+"\""); + response.raw().setContentType(format.getContentType()); + response.raw().setHeader(CONTENT_DISPOSITION, (inline ? "inline" : "attachment") + "; filename=\"example." + format.getExt() + "\""); streamAndClose(is, response.raw().getOutputStream()); - }catch (Exception e){ + } catch (Exception e) { notFound(response); } return 0; }); + + // curl --form template=@myfile.odt -data=@data.json -asset1=myasset.jpg http://document-service/compile > myfile.pdf post("/compile", (request, response) -> { try { StopWatch sw = StopWatch.createStarted(); - FileResult result = templateCompiler.compile(request.raw().getInputStream(), request.queryParams("format"), request.queryMap().hasKey("error")); + Template template; + if (request.contentType().startsWith(MULTIPART_FORM_DATA)) { + request.attribute("org.eclipse.jetty.multipartConfig", new MultipartConfigElement("/temp")); + template = Template.fromFormData(request.raw().getParts(), request.queryParams("format")); + } else { + template = Template.fromZip(request.raw().getInputStream(), request.queryParams("format")); + } + FileResult result = templateCompiler.compile(template, request.queryMap().hasKey("error")); response.header("Content-Type", result.contentType); response.header("Content-Length", "" + result.target.length()); try { @@ -117,14 +129,17 @@ public SparkServer(Config config) { } finally { result.release(); } - System.out.println("request took: " + sw.getTime(TimeUnit.MILLISECONDS)); - } catch(EofException | MultipartStream.MalformedStreamException eof){ - try{ + log.info("request took: " + sw.getTime(TimeUnit.MILLISECONDS)); + } catch (EofException | MultipartStream.MalformedStreamException eof) { + try { response.raw().getOutputStream().close(); - }catch (Exception idc){} + } catch (Exception idc) { + } } catch (CompilationException e) { + e.printStackTrace(); error(422, response, e); } catch (BadRequestException e) { + e.printStackTrace(); error(HttpURLConnection.HTTP_BAD_REQUEST, response, e); } catch (NotImplementedException e) { error(HttpURLConnection.HTTP_NOT_IMPLEMENTED, response, e); @@ -135,33 +150,50 @@ public SparkServer(Config config) { } return 0; }); - get("/extension", (request, response) -> { + + get("/extension", (request, response) -> + + { try { //request.queryParams("app") //app is meant for future releases //right now there is just libre so we can ignore this param - Extension extension = libreOfficeAssistant.getExtension(request.queryParams("os")); - response.raw().setContentType(extension.contentType); - response.raw().setHeader("Content-Disposition", "attachment; filename=\"" + extension.fileName+"\""); - streamAndClose(extension.inputStream, response.raw().getOutputStream()); + Extension extension = templateFormatter.getExtension(request.queryParams("os")); + response.raw().setContentType(extension.getContentType()); + response.raw().setHeader(CONTENT_DISPOSITION, "attachment; filename=\"" + extension.getFileName() + "\""); + streamAndClose(extension.getInputStream(), response.raw().getOutputStream()); } catch (Exception e) { notFound(response); } return 0; }); - post("/vars", (request, response) -> { + + post("/vars", (request, response) -> + { try { + Template template; + if (request.contentType().startsWith("application/x-www-form-urlencoded")) { + InputStream is = request.raw().getInputStream(); + template = Template.fromODT(is); + is.close(); + } else if (request.contentType().startsWith("multipart/form-data")) { + request.attribute("org.eclipse.jetty.multipartConfig", new MultipartConfigElement("/temp")); + template = Template.fromFormData(request.raw().getParts(), request.queryParams("format")); + } else { + template = Template.fromZip(request.raw().getInputStream(), request.queryParams("format")); + } + response.type(JSON_CONTENT_TYPE); OutputStream os = response.raw().getOutputStream(); - InputStream is = request.raw().getInputStream(); - os.write(Json.toJson(templateCompiler.vars(is, request.queryParams("prefix"))).getBytes(defaultCharset)); + Set result = templateCompiler.vars(template, request.queryParams("prefix")); + os.write(Json.toJson(result).getBytes(defaultCharset)); os.flush(); os.close(); - is.close(); - } catch(org.eclipse.jetty.io.EofException | MultipartStream.MalformedStreamException eof){ - try{ + } catch (org.eclipse.jetty.io.EofException | MultipartStream.MalformedStreamException eof) { + try { response.raw().getOutputStream().close(); - }catch (Exception idc){} + } catch (Exception idc) { + } } catch (CompilationException e) { error(422, response, e); } catch (BadRequestException e) { @@ -172,6 +204,7 @@ public SparkServer(Config config) { error(HttpURLConnection.HTTP_UNAVAILABLE, response, e); } catch (Exception e) { error(HttpURLConnection.HTTP_INTERNAL_ERROR, response, e); + e.printStackTrace(); } return 0; }); @@ -179,11 +212,11 @@ public SparkServer(Config config) { log.info("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]]][ Document Service started ][[[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); } - private void api(Response response){ - try{ + private void api(Response response) { + try { response.type("text/html; charset=UTF-8"); streamAndClose(SparkServer.class.getResourceAsStream("/api.html"), response.raw().getOutputStream()); - }catch (Exception e){ + } catch (Exception e) { notFound(response); } } @@ -194,7 +227,7 @@ private InputStream getODTAsPDFFromResources(Config config, String name) throws return new FileInputStream(f); } else { streamAndClose(SparkServer.class.getResourceAsStream("/" + name), new FileOutputStream(f)); - libreOfficeAssistant.Convert(f, f, "pdf"); + templateFormatter.Convert(f, f, "pdf", false); return new FileInputStream(f); } } @@ -209,31 +242,34 @@ private InputStream getDirAsPDFFromResources(Config config, String name) throws return null; } //compile - FileResult result = templateCompiler.compile(new FileInputStream(zip), "pdf", false); + + Template template = Template.fromZip(new FileInputStream(zip), "pdf"); + template.setFormat("pdf"); + FileResult result = templateCompiler.compile(template, false); Files.move(result.target.toPath(), f.toPath(), StandardCopyOption.REPLACE_EXISTING); return new FileInputStream(f); } } - private void removeTheDiskCacheOfDocs(){ + private void removeTheDiskCacheOfDocs() { //remove the disk cache to load it again from the jar new File(config.getTmpFolder(), "how.it.works.odt").delete(); - try{ + try { //remove the disk cache to load it again from the jar FileUtils.deleteDirectory(new File(config.getTmpFolder(), "example")); - }catch (Exception e){ + } catch (Exception e) { //not important } } private void notFound(Response response) { - try{ + try { response.status(HttpURLConnection.HTTP_NOT_FOUND); OutputStream os = response.raw().getOutputStream(); //close the response stream to prevent spark from fooling around with the return value os.flush(); os.close(); - }catch (Exception e){ + } catch (Exception e) { //not important System.err.println("couldn't send the not found response"); } @@ -247,19 +283,19 @@ private void streamAndClose(InputStream is, OutputStream os) throws Exception { } private void error(int status, Response response, Exception e) { - try{ + try { response.status(status); response.type(TEXT_CONTENT_TYPE); OutputStream os = response.raw().getOutputStream(); String msg = e.getMessage(); - if(msg == null){ + if (msg == null) { msg = "null"; } os.write(msg.getBytes(defaultCharset)); os.flush(); os.close(); - }catch (Exception ee){ + } catch (Exception ee) { System.err.println("couldn't send the error response"); } } -} \ No newline at end of file +} diff --git a/src/main/java/com/proxeus/compiler/jtwig/MyConfiguration.java b/src/main/java/com/proxeus/compiler/jtwig/MyConfiguration.java index a3a512f..c3128d1 100644 --- a/src/main/java/com/proxeus/compiler/jtwig/MyConfiguration.java +++ b/src/main/java/com/proxeus/compiler/jtwig/MyConfiguration.java @@ -1,7 +1,6 @@ package com.proxeus.compiler.jtwig; import com.google.common.collect.ImmutableMap; - import org.jtwig.environment.EnvironmentConfiguration; import org.jtwig.environment.initializer.EnvironmentInitializer; import org.jtwig.escape.EscapeEngine; diff --git a/src/main/java/com/proxeus/compiler/jtwig/MyDefaultJtwigParserConfiguration.java b/src/main/java/com/proxeus/compiler/jtwig/MyDefaultJtwigParserConfiguration.java index a51b07d..e46f921 100644 --- a/src/main/java/com/proxeus/compiler/jtwig/MyDefaultJtwigParserConfiguration.java +++ b/src/main/java/com/proxeus/compiler/jtwig/MyDefaultJtwigParserConfiguration.java @@ -1,37 +1,11 @@ package com.proxeus.compiler.jtwig; import com.google.common.base.Optional; - import org.jtwig.parser.addon.AddonParserProvider; import org.jtwig.parser.config.DefaultSyntaxConfiguration; import org.jtwig.parser.config.JtwigParserConfiguration; -import org.jtwig.parser.parboiled.expression.test.DefinedTestExpressionParser; -import org.jtwig.parser.parboiled.expression.test.DivisibleByTestExpressionParser; -import org.jtwig.parser.parboiled.expression.test.FunctionTestExpressionParser; -import org.jtwig.parser.parboiled.expression.test.IsFunctionTestExpressionParser; -import org.jtwig.parser.parboiled.expression.test.NullTestExpressionParser; -import org.jtwig.parser.parboiled.expression.test.SameAsTestExpressionParser; -import org.jtwig.parser.parboiled.expression.test.TestExpressionParser; -import org.jtwig.render.expression.calculator.operation.binary.impl.AndOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.CompositionOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.ConcatOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.DifferentOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.DivideOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.EquivalentOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.GreaterOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.GreaterOrEqualOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.InOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.IntDivideOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.IntMultiplyOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.LessOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.LessOrEqualOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.MatchesOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.ModOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.MultiplyOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.OrOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.SelectionOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.SubtractOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.SumOperator; +import org.jtwig.parser.parboiled.expression.test.*; +import org.jtwig.render.expression.calculator.operation.binary.impl.*; import org.jtwig.render.expression.calculator.operation.unary.impl.NegativeUnaryOperator; import org.jtwig.render.expression.calculator.operation.unary.impl.NotUnaryOperator; diff --git a/src/main/java/com/proxeus/compiler/jtwig/MyJTwigCompiler.java b/src/main/java/com/proxeus/compiler/jtwig/MyJTwigCompiler.java index 5551176..c62d144 100644 --- a/src/main/java/com/proxeus/compiler/jtwig/MyJTwigCompiler.java +++ b/src/main/java/com/proxeus/compiler/jtwig/MyJTwigCompiler.java @@ -1,7 +1,6 @@ package com.proxeus.compiler.jtwig; import com.proxeus.error.CompilationException; - import org.jtwig.JtwigModel; import org.jtwig.JtwigTemplate; import org.jtwig.environment.Environment; diff --git a/src/main/java/com/proxeus/compiler/jtwig/MyRenderConfiguration.java b/src/main/java/com/proxeus/compiler/jtwig/MyRenderConfiguration.java index 4f1823a..e0181d8 100644 --- a/src/main/java/com/proxeus/compiler/jtwig/MyRenderConfiguration.java +++ b/src/main/java/com/proxeus/compiler/jtwig/MyRenderConfiguration.java @@ -1,145 +1,26 @@ package com.proxeus.compiler.jtwig; import com.google.common.collect.ImmutableMap; - import org.jtwig.macro.render.ImportRender; -import org.jtwig.model.expression.BinaryOperationExpression; -import org.jtwig.model.expression.ComprehensionListExpression; -import org.jtwig.model.expression.ConstantExpression; -import org.jtwig.model.expression.EnumeratedListExpression; -import org.jtwig.model.expression.Expression; -import org.jtwig.model.expression.FunctionExpression; -import org.jtwig.model.expression.MapExpression; -import org.jtwig.model.expression.MapSelectionExpression; -import org.jtwig.model.expression.TernaryOperationExpression; -import org.jtwig.model.expression.TestOperationExpression; -import org.jtwig.model.expression.UnaryOperationExpression; -import org.jtwig.model.expression.VariableExpression; -import org.jtwig.model.expression.test.DefinedTestExpression; -import org.jtwig.model.expression.test.DivisibleByTestExpression; -import org.jtwig.model.expression.test.FunctionTestExpression; -import org.jtwig.model.expression.test.IsFunctionTestExpression; -import org.jtwig.model.expression.test.NotTestExpression; -import org.jtwig.model.expression.test.NullTestExpression; -import org.jtwig.model.expression.test.SameAsTestExpression; -import org.jtwig.model.expression.test.TestExpression; -import org.jtwig.model.tree.AutoEscapeNode; -import org.jtwig.model.tree.BlockNode; -import org.jtwig.model.tree.CompositeNode; -import org.jtwig.model.tree.ContentEscapeNode; -import org.jtwig.model.tree.DoNode; -import org.jtwig.model.tree.EmbedNode; -import org.jtwig.model.tree.ExtendsNode; -import org.jtwig.model.tree.FilterNode; -import org.jtwig.model.tree.FlushNode; -import org.jtwig.model.tree.ForLoopNode; -import org.jtwig.model.tree.IfNode; -import org.jtwig.model.tree.ImportNode; -import org.jtwig.model.tree.ImportSelfNode; -import org.jtwig.model.tree.IncludeNode; -import org.jtwig.model.tree.MacroNode; -import org.jtwig.model.tree.Node; -import org.jtwig.model.tree.OutputNode; -import org.jtwig.model.tree.OverrideBlockNode; -import org.jtwig.model.tree.SetNode; -import org.jtwig.model.tree.TextNode; -import org.jtwig.model.tree.VerbatimNode; +import org.jtwig.model.expression.*; +import org.jtwig.model.expression.test.*; +import org.jtwig.model.tree.*; import org.jtwig.render.config.RenderConfiguration; -import org.jtwig.render.expression.calculator.BinaryOperationExpressionCalculator; -import org.jtwig.render.expression.calculator.ComprehensionListExpressionCalculator; -import org.jtwig.render.expression.calculator.ConstantExpressionCalculator; -import org.jtwig.render.expression.calculator.EnumeratedListExpressionCalculator; -import org.jtwig.render.expression.calculator.ExpressionCalculator; -import org.jtwig.render.expression.calculator.FunctionArgumentsFactory; -import org.jtwig.render.expression.calculator.FunctionExpressionCalculator; -import org.jtwig.render.expression.calculator.MapExpressionCalculator; -import org.jtwig.render.expression.calculator.MapSelectionExpressionCalculator; -import org.jtwig.render.expression.calculator.TernaryExpressionCalculator; -import org.jtwig.render.expression.calculator.TestOperationExpressionCalculator; -import org.jtwig.render.expression.calculator.UnaryOperationExpressionCalculator; -import org.jtwig.render.expression.calculator.VariableExpressionCalculator; +import org.jtwig.render.expression.calculator.*; import org.jtwig.render.expression.calculator.operation.binary.BinaryOperator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.AndOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.BinaryOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.BooleanOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.CompositionOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.ConcatOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.DifferentOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.DivideOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.EquivalentOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.GreaterOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.GreaterOrEqualOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.InOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.IntegerDivideOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.IntegerMultiplyOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.LessOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.LessOrEqualOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.MatchesOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.MathOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.ModOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.MultiplyOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.OrOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.SimpleOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.SubtractOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.calculators.SumOperationCalculator; +import org.jtwig.render.expression.calculator.operation.binary.calculators.*; import org.jtwig.render.expression.calculator.operation.binary.calculators.selection.SelectionErrorMessageGenerator; import org.jtwig.render.expression.calculator.operation.binary.calculators.selection.SelectionOperationCalculator; -import org.jtwig.render.expression.calculator.operation.binary.impl.AndOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.CompositionOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.ConcatOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.DifferentOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.DivideOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.EquivalentOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.GreaterOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.GreaterOrEqualOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.InOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.IntDivideOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.IntMultiplyOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.LessOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.LessOrEqualOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.MatchesOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.ModOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.MultiplyOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.OrOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.SelectionOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.SubtractOperator; -import org.jtwig.render.expression.calculator.operation.binary.impl.SumOperator; +import org.jtwig.render.expression.calculator.operation.binary.impl.*; import org.jtwig.render.expression.calculator.operation.unary.UnaryOperator; import org.jtwig.render.expression.calculator.operation.unary.calculators.NegativeOperationCalculator; import org.jtwig.render.expression.calculator.operation.unary.calculators.NotOperationCalculator; import org.jtwig.render.expression.calculator.operation.unary.calculators.UnaryOperationCalculator; import org.jtwig.render.expression.calculator.operation.unary.impl.NegativeUnaryOperator; import org.jtwig.render.expression.calculator.operation.unary.impl.NotUnaryOperator; -import org.jtwig.render.expression.test.calculator.DefinedTestExpressionCalculator; -import org.jtwig.render.expression.test.calculator.DivisibleByTestExpressionCalculator; -import org.jtwig.render.expression.test.calculator.FunctionTestExpressionCalculator; -import org.jtwig.render.expression.test.calculator.IsFunctionTestExpressionCalculator; -import org.jtwig.render.expression.test.calculator.NotTestExpressionCalculator; -import org.jtwig.render.expression.test.calculator.NullTestExpressionCalculator; -import org.jtwig.render.expression.test.calculator.SameAsTestExpressionCalculator; -import org.jtwig.render.expression.test.calculator.TestExpressionCalculator; +import org.jtwig.render.expression.test.calculator.*; import org.jtwig.render.listeners.StagedRenderListener; -import org.jtwig.render.node.renderer.AutoEscapeNodeRender; -import org.jtwig.render.node.renderer.BlockNodeRender; -import org.jtwig.render.node.renderer.CompositeNodeRender; -import org.jtwig.render.node.renderer.ContentEscapeNodeRender; -import org.jtwig.render.node.renderer.DoNodeRender; -import org.jtwig.render.node.renderer.EmbedNodeRender; -import org.jtwig.render.node.renderer.ExtendsNodeRender; -import org.jtwig.render.node.renderer.FilterNodeRender; -import org.jtwig.render.node.renderer.FlushNodeRender; -import org.jtwig.render.node.renderer.ForLoopNodeRender; -import org.jtwig.render.node.renderer.IfNodeRender; -import org.jtwig.render.node.renderer.ImportNodeRender; -import org.jtwig.render.node.renderer.ImportSelfNodeRender; -import org.jtwig.render.node.renderer.IncludeNodeRender; -import org.jtwig.render.node.renderer.MacroNodeRender; -import org.jtwig.render.node.renderer.NodeRender; -import org.jtwig.render.node.renderer.OutputNodeRender; -import org.jtwig.render.node.renderer.OverrideBlockNodeRender; -import org.jtwig.render.node.renderer.SetNodeRender; -import org.jtwig.render.node.renderer.TextNodeRender; -import org.jtwig.render.node.renderer.VerbatimNodeRender; +import org.jtwig.render.node.renderer.*; import java.nio.charset.Charset; import java.util.ArrayList; diff --git a/src/main/java/com/proxeus/compiler/jtwig/MyResourceConfiguration.java b/src/main/java/com/proxeus/compiler/jtwig/MyResourceConfiguration.java index 4e242db..12a68a8 100644 --- a/src/main/java/com/proxeus/compiler/jtwig/MyResourceConfiguration.java +++ b/src/main/java/com/proxeus/compiler/jtwig/MyResourceConfiguration.java @@ -1,7 +1,6 @@ package com.proxeus.compiler.jtwig; import com.google.common.collect.ImmutableList; - import org.jtwig.resource.config.DefaultResourceConfiguration; import org.jtwig.resource.config.ResourceConfiguration; import org.jtwig.resource.loader.ClasspathResourceLoader; diff --git a/src/main/java/com/proxeus/compiler/jtwig/ResourceServiceFixForInlineInputStream.java b/src/main/java/com/proxeus/compiler/jtwig/ResourceServiceFixForInlineInputStream.java index 2880328..30793e9 100644 --- a/src/main/java/com/proxeus/compiler/jtwig/ResourceServiceFixForInlineInputStream.java +++ b/src/main/java/com/proxeus/compiler/jtwig/ResourceServiceFixForInlineInputStream.java @@ -1,7 +1,6 @@ package com.proxeus.compiler.jtwig; import com.google.common.base.Optional; - import org.jtwig.resource.ResourceService; import org.jtwig.resource.loader.ResourceLoader; import org.jtwig.resource.loader.TypedResourceLoader; diff --git a/src/main/java/com/proxeus/document/AssetFile.java b/src/main/java/com/proxeus/document/AssetFile.java index 0080ed4..990adb3 100644 --- a/src/main/java/com/proxeus/document/AssetFile.java +++ b/src/main/java/com/proxeus/document/AssetFile.java @@ -2,6 +2,9 @@ import org.apache.commons.io.IOUtils; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -9,16 +12,11 @@ import java.net.URL; import java.net.URLConnection; import java.util.Collection; -import java.util.Iterator; import java.util.Map; import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.imageio.ImageIO; -import javax.imageio.ImageReader; -import javax.imageio.stream.ImageInputStream; - /** * AssetFile makes it possible to transform a file out of: * 1. URL like http://myimagelink @@ -37,7 +35,6 @@ public class AssetFile { public String newZipPath; public File src; public File dst; - //public String ext; activate when needed public static AssetFile find(Object localRemoteOrEmbeddedFileObject, File tmpDir){ try{ @@ -112,7 +109,6 @@ private static AssetFile provideImageFileWithExtIfPossible(String localOrRemoteP while (localOrRemotePath.startsWith("/")) { localOrRemotePath = localOrRemotePath.substring(1); } - //return getLocalFileToResultMap(localFile); ---activate when needed--- AssetFile result = new AssetFile(); result.src = new File(cacheDir, localOrRemotePath); return result; @@ -121,40 +117,12 @@ private static AssetFile provideImageFileWithExtIfPossible(String localOrRemoteP } } else {//remote url try { - //boolean needToReadFileForExt = false; URL url = new URL(localOrRemotePath); - /** ---activate when needed--- - String fileExt = localOrRemotePath.substring(localOrRemotePath.lastIndexOf('/')).toLowerCase(); - if (fileExt.contains("?")) { - fileExt = fileExt.substring(0, fileExt.indexOf('?')); - }*/ String fileName = UUID.randomUUID().toString(); - /* ---activate when needed--- - try { - fileExt = fileExt.substring(fileExt.lastIndexOf('.')); - if (isImageExtValid(fileExt)) { - fileName = fileName + fileExt; - } else { - needToReadFileForExt = true; - } - } catch (Exception e) { - needToReadFileForExt = true; - }*/ File downloadedImage = new File(cacheDir, fileName); copyURLToFile(url, downloadedImage); AssetFile result = new AssetFile(); result.src = downloadedImage; - /* ---activate when needed--- - if (needToReadFileForExt) { - fileExt = getImageExt(downloadedImage); - } - if (fileExt == null) { - result.src.delete(); - // we weren't able to determine the extension - // let's break here as the file is either corrupt or not an image - return null; - }*/ - //result.ext = fileExt; return result; } catch (Exception dontCare) { dontCare.printStackTrace(); @@ -163,25 +131,6 @@ private static AssetFile provideImageFileWithExtIfPossible(String localOrRemoteP return null; } - /** - * Gets image ext. - * - * @param file the file - * @return .png, .jpg etc.. - * @throws Exception the exception - */ - private static String getImageExt(File file) throws Exception { - ImageInputStream iis = ImageIO.createImageInputStream(file); - Iterator imageReaders = ImageIO.getImageReaders(iis); - String fileExt = null; - if (imageReaders.hasNext()) { - ImageReader reader = imageReaders.next(); - fileExt = "." + reader.getFormatName().toLowerCase(); - } - iis.close(); - return fileExt; - } - /** * Copy url to file. * @@ -232,32 +181,6 @@ private static FileOutputStream openOutputStream(File file) throws IOException { return new FileOutputStream(file); } - private static AssetFile getLocalFileToResultMap(AssetFile result, File localFile) throws Exception { - if (localFile.exists()) { - String fileExt = localFile.getName().toLowerCase(); - try { - fileExt = fileExt.substring(fileExt.lastIndexOf('.')); - if (!isImageExtValid(fileExt)) { - fileExt = getImageExt(localFile); - } - } catch (StringIndexOutOfBoundsException e) { - fileExt = getImageExt(localFile); - } - if (isImageExtValid(fileExt)) { - if(result == null){ - result = new AssetFile(); - } - result.src = localFile; - //result.ext = fileExt; ---activate when needed--- - } - } - return result; - } - - private static boolean isImageExtValid(String fileExt) { - return fileExt.length() >= 4 && fileExt.length() <= 5; - } - } diff --git a/src/main/java/com/proxeus/document/DocumentCompilerIF.java b/src/main/java/com/proxeus/document/DocumentCompiler.java similarity index 91% rename from src/main/java/com/proxeus/document/DocumentCompilerIF.java rename to src/main/java/com/proxeus/document/DocumentCompiler.java index 144ed33..4cac90a 100644 --- a/src/main/java/com/proxeus/document/DocumentCompilerIF.java +++ b/src/main/java/com/proxeus/document/DocumentCompiler.java @@ -7,9 +7,7 @@ * If other formats based on XML are going to be implemented, they can simply use this * interface to communicate with the underlying format specific compiler. */ -public interface DocumentCompilerIF { +public interface DocumentCompiler { FileResult Compile(Template template) throws Exception; Set Vars(Template template, String varPrefix) throws Exception; -} - - +} \ No newline at end of file diff --git a/src/main/java/com/proxeus/document/FileResult.java b/src/main/java/com/proxeus/document/FileResult.java index 7069653..99ec2e1 100644 --- a/src/main/java/com/proxeus/document/FileResult.java +++ b/src/main/java/com/proxeus/document/FileResult.java @@ -1,5 +1,7 @@ package com.proxeus.document; +import org.apache.commons.lang3.builder.ToStringBuilder; + import java.io.File; /** @@ -26,6 +28,10 @@ public void release(){ contentType = null; template = null; } + + public String toString(){ + return ToStringBuilder.reflectionToString(this); + } } diff --git a/src/main/java/com/proxeus/document/FontInstaller.java b/src/main/java/com/proxeus/document/FontInstaller.java index dabbce5..fe15549 100644 --- a/src/main/java/com/proxeus/document/FontInstaller.java +++ b/src/main/java/com/proxeus/document/FontInstaller.java @@ -1,6 +1,8 @@ package com.proxeus.document; -import java.awt.Font; +import org.apache.log4j.Logger; + +import java.awt.*; import java.io.File; import java.io.FileInputStream; import java.nio.file.Files; @@ -11,6 +13,8 @@ * Installs fonts on a Linux system. */ public class FontInstaller { + private Logger log = Logger.getLogger(this.getClass()); + private File userFontsDir; private int lastFontCount = 0; private int currentFontCount = 0; @@ -109,7 +113,7 @@ private void CmdforceFcCache(){ try { Runtime.getRuntime().exec("fc-cache -f " + userFontsDir.getAbsolutePath()).waitFor(5, TimeUnit.SECONDS); } catch (Exception e) { - e.printStackTrace(); + log.info("Cannot execute fc-cache -f"); } } } diff --git a/src/main/java/com/proxeus/document/Template.java b/src/main/java/com/proxeus/document/Template.java index 334da83..4fa8bfc 100644 --- a/src/main/java/com/proxeus/document/Template.java +++ b/src/main/java/com/proxeus/document/Template.java @@ -1,27 +1,51 @@ package com.proxeus.document; +import com.proxeus.error.BadRequestException; +import com.proxeus.util.Json; +import com.proxeus.util.zip.EntryFilter; +import com.proxeus.util.zip.Zip; import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.log4j.Logger; -import java.io.File; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import javax.servlet.http.Part; +import java.io.*; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.*; +import java.util.zip.ZipEntry; + +import static com.proxeus.document.TemplateType.DOCX; +import static com.proxeus.document.TemplateType.ODT; /** * Template simplifies the compile interface. */ public class Template { - public TemplateType type; - public File src; - public Map data; - public File tmpDir; - public String format; - public boolean embedError; + private TemplateType type; + private File src; + private Map data; + private File tmpDir; + private String format; + private boolean embedError; + private String cacheDir = System.getProperty("document.template.cache.dir"); + private String alternateCacheDir = System.getProperty("java.io.tmpdir"); + + + public String toString() { + return new ToStringBuilder(this). + append("type", type). + append("src", src). + append("data", data). + append("tmpDir", tmpDir). + append("format", format). + append("embedError", embedError).toString(); + } public Template() throws Exception { + this.data = new HashMap<>(); createCacheDir(); } @@ -32,16 +56,118 @@ public Template(File src, Map data) throws Exception { public Template(File src, Map data, String format) throws Exception { this.src = src; this.data = data; + if (this.data == null) { + this.data = new HashMap<>(); + } this.format = format; createCacheDir(); } - private void createCacheDir() throws Exception { - String cacheDir = System.getProperty("document.template.cache.dir"); - if(cacheDir == null || cacheDir.isEmpty()){ - cacheDir = System.getProperty("java.io.tmpdir"); + public static Template fromFormData(Collection parts, String format) throws Exception { + if (format == null) { + format = "pdf"; + } + + Template template = new Template(); + for (Part part : parts) { + try (InputStream inputStream = part.getInputStream()) { + String filename = part.getSubmittedFileName(); + processEntry(template, filename, inputStream, false); + } + } + + template.setFormat(format); + return template; + } + + public static Template fromZip(InputStream zipStream, String format) throws Exception { + if (format == null) { + format = "pdf"; + } + + Template template = new Template(); + try { + extractZIP(template, zipStream); + template.setFormat(format); + return template; + } catch (Exception e) { + throw new BadRequestException("Please read the specification for creating the request with the zip package. zip[tmpl.odt,data.json,assets1,asset2...]"); + } + } + + public static Template fromODT(InputStream inputStream) throws Exception { + Template template = new Template(); + try { + template.setSrc(new File(template.getTmpDir(), "tmpl.odt")); + FileUtils.copyToFile(inputStream, template.getSrc()); + return template; + } catch (Exception e) { + throw new BadRequestException("Please read the specification for the vars request."); + } + } + + /** + * Extracting the ZIP package. + * Structure: + * -zip + * ---- tmpl.odt | tmpl.docx //only one template supported + * ---- data.json //the json data the template is going to be resolved with + * ---- asset1 // assets that should be referenced in the json data + * ---- asset2 + * ---- asset3 + * + * @param template The template object to initialize + * @param zipStream ZIP package input stream + * @throws Exception + */ + private static void extractZIP(Template template, InputStream zipStream) throws Exception { + Zip.extract(zipStream, (zipEntry, zipInputStream) -> processEntry(template, zipEntry.getName(), zipInputStream, zipEntry.isDirectory())); + } + + @SuppressWarnings("unchecked") + private static void processEntry(Template template, String name, InputStream inputStream, boolean isDirectory) throws IOException { + if (name.toLowerCase().endsWith(".odt")) { + //found an odt template inside the zip + template.setSrc(inputStreamToFile(inputStream, template.getTmpDir(), "tmpl.odt", isDirectory)); + if (!template.getSrc().exists() || template.getSrc().isDirectory()) { + throw new IllegalStateException("couldn't process template odt"); + } + } else if (name.toLowerCase().endsWith(".docx")) { + //found a docx template inside the zip + template.setSrc(inputStreamToFile(inputStream, template.getTmpDir(), "tmpl.docx", isDirectory)); + if (!template.getSrc().exists() || template.getSrc().isDirectory()) { + throw new IllegalStateException("couldn't process template docx"); + } + } else if (name.toLowerCase().endsWith(".json")) { + //the json data the template is going to be resolved with + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + IOUtils.copy(inputStream, outputStream); + template.setData(Json.fromJson(outputStream.toByteArray(), Map.class)); + } else { + //other assets that should be referenced in the json data + inputStreamToFile(inputStream, template.getTmpDir(), name, isDirectory); + } + } + + private static File inputStreamToFile(InputStream inputStream, File tmpDir, String fname, boolean isDirectory) throws IOException { + File file = new File(tmpDir, fname); + if (isDirectory) { + if (!file.exists()) { + if (!file.mkdirs()) { + throw new IOException("Could not create: " + file.getAbsolutePath()); + } + } + } else { + try (FileOutputStream fileOutputStream = new FileOutputStream(file)) { + IOUtils.copy(inputStream, fileOutputStream); + fileOutputStream.flush(); + } } - tmpDir = new File(cacheDir, UUID.randomUUID().toString()); + return file; + } + + private void createCacheDir() throws Exception { + tmpDir = new File(getCacheDir(), UUID.randomUUID().toString()); ensureDirs(); } @@ -51,23 +177,27 @@ public void ensureDirs() throws Exception { } } - public Map getDataCopy(){ + private String getCacheDir() { + return (cacheDir == null || cacheDir.isEmpty()) ? alternateCacheDir : cacheDir; + } + + public Map getDataCopy() { return copy(data); } - public void release(){ - try{ + public void release() { + try { FileUtils.deleteDirectory(tmpDir); - }catch(Exception e){ - System.err.println("error when deleting directory: "+ tmpDir.getAbsolutePath()); + } catch (Exception e) { + System.err.println("error when deleting directory: " + tmpDir.getAbsolutePath()); } src = null; data = null; tmpDir = null; } - private static Map copy(Map data){ - if(data == null){ + private static Map copy(Map data) { + if (data == null) { return new HashMap<>(0); } Map om = new HashMap<>(data.size()); @@ -76,39 +206,87 @@ private static Map copy(Map data){ } @SuppressWarnings("unchecked") - private static void list(List newList, Collection orgList){ - for(Object o : orgList){ - if(o instanceof Map){ - Map orgm = ((Map)o); + private static void list(List newList, Collection orgList) { + for (Object o : orgList) { + if (o instanceof Map) { + Map orgm = ((Map) o); Map om = new HashMap<>(orgm.size()); map(om, orgm); - }else if(o instanceof Collection){ - Collection innerOrgList = (Collection)o; + } else if (o instanceof Collection) { + Collection innerOrgList = (Collection) o; List list = new ArrayList(orgList.size()); list(list, innerOrgList); newList.add(list); - }else{ + } else { newList.add(o); } } } @SuppressWarnings("unchecked") - private static void map(Map newMap, Map data){ + private static void map(Map newMap, Map data) { for (Map.Entry entry : data.entrySet()) { Object o = entry.getValue(); - if(o instanceof Map){ - Map orgm = ((Map)o); + if (o instanceof Map) { + Map orgm = ((Map) o); Map om = new HashMap<>(orgm.size()); map(om, orgm); - }else if(o instanceof Collection){ - Collection orgList = (Collection)o; + } else if (o instanceof Collection) { + Collection orgList = (Collection) o; List list = new ArrayList(orgList.size()); list(list, orgList); } newMap.put(entry.getKey(), o); } } + + public File getSrc() { + if (src == null) { + throw new IllegalStateException("No source in Template"); + } + return src; + } + + public void setSrc(File src) { + this.src = src; + } + + public File getTmpDir() { + return tmpDir; + } + + public TemplateType getType() { + switch (FilenameUtils.getExtension(src.getName())) { + case "docx": + return DOCX; + default: + return ODT; + } + } + + public boolean isEmbedError() { + return embedError; + } + + public void setEmbedError(boolean embedError) { + this.embedError = embedError; + } + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + + public Map getData() { + return data; + } + + public void setData(Map data) { + this.data = data; + } } diff --git a/src/main/java/com/proxeus/document/TemplateCompiler.java b/src/main/java/com/proxeus/document/TemplateCompiler.java index 46751dc..f5e601b 100644 --- a/src/main/java/com/proxeus/document/TemplateCompiler.java +++ b/src/main/java/com/proxeus/document/TemplateCompiler.java @@ -1,17 +1,15 @@ package com.proxeus.document; -import com.proxeus.compiler.jtwig.MyJTwigCompiler; -import com.proxeus.document.docx.DOCXCompiler; import com.proxeus.document.odt.ODTCompiler; import com.proxeus.error.BadRequestException; -import com.proxeus.office.libre.LibreOfficeAssistant; -import com.proxeus.office.microsoft.MicrosoftOfficeAssistant; import com.proxeus.util.Json; import com.proxeus.util.zip.EntryFilter; import com.proxeus.util.zip.Zip; - +import com.proxeus.xml.template.TemplateHandlerFactory; +import com.proxeus.xml.template.TemplateVarParserFactory; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; +import org.apache.log4j.Logger; import java.io.File; import java.io.InputStream; @@ -25,116 +23,28 @@ public class TemplateCompiler { + private Logger log = Logger.getLogger(this.getClass()); + private ODTCompiler odtCompiler; - private DOCXCompiler docxCompiler; - private MyJTwigCompiler compiler; - public TemplateCompiler(String cacheFolder, LibreOfficeAssistant libreOfficeAssistant) throws Exception{ - compiler = new MyJTwigCompiler(); - odtCompiler = new ODTCompiler(cacheFolder, compiler, libreOfficeAssistant); - docxCompiler = new DOCXCompiler(cacheFolder, compiler, new MicrosoftOfficeAssistant()); + public TemplateCompiler(String cacheFolder, TemplateFormatter templateFormatter, TemplateHandlerFactory templateHandlerFactory, TemplateVarParserFactory templateVarParserFactory) throws Exception { + this.odtCompiler = new ODTCompiler(cacheFolder, templateFormatter, templateHandlerFactory, templateVarParserFactory); } - public FileResult compile(InputStream zipStream, String format, boolean embedError) throws Exception{ - Template template = provideTemplateFromZIP(zipStream, format); - template.embedError = embedError; + public FileResult compile(Template template, boolean embedError) throws Exception { + template.setEmbedError(embedError); return getCompiler(template).Compile(template); } - public Set vars(InputStream odtStream, String varPrefix) throws Exception{ - Template template = provideTemplateFromODT(odtStream); + public Set vars(Template template, String varPrefix) throws Exception { return getCompiler(template).Vars(template, varPrefix); } - private DocumentCompilerIF getCompiler(Template template){ - switch (template.type) { - case ODT:return odtCompiler; - case DOCX:return docxCompiler; - - default: return odtCompiler; - } - } - - private Template provideTemplateFromZIP(InputStream zipStream, String format) throws Exception { - try{ - if (format == null) { - format = "pdf"; - } - Template template = extractZIP(zipStream); - template.format = format; - return template; - }catch (Exception e){ - throw new BadRequestException("Please read the specification for creating the request with the zip package. zip[tmpl.odt,data.json,assets1,asset2...]"); - } - } - - private Template provideTemplateFromODT(InputStream zipStream) throws Exception { - try{ - Template template = new Template(); - template.src = new File(template.tmpDir, "tmpl"); - template.type = TemplateType.ODT; - FileUtils.copyToFile(zipStream, template.src); - return template; - }catch (Exception e){ - throw new BadRequestException("Please read the specification for the vars request."); + private DocumentCompiler getCompiler(Template template) { + switch (template.getType()) { + case ODT: + default: + return odtCompiler; } } - - /** - * Extracting the ZIP package. - * Structure: - * -zip - * ---- tmpl.odt | tmpl.docx //only one template supported - * ---- data.json //the json data the template is going to be resolved with - * ---- asset1 // assets that should be referenced in the json data - * ---- asset2 - * ---- asset3 - * @param zipStream ZIP package - * @return a Template that should be ready to be compiled - */ - @SuppressWarnings("unchecked") - private Template extractZIP(InputStream zipStream) throws Exception { - Template template = new Template(); - Zip.extract(zipStream, new EntryFilter() { - public void next(ZipEntry zipEntry, InputStream zipInputStream) throws Exception { - if (zipEntry.getName().toLowerCase().endsWith(".odt")) { - //found an odt template inside the zip - template.type = ODT; - template.src = Zip.zipEntryToFile(zipEntry, zipInputStream, template.tmpDir, "tmpl.odt"); - if (!template.src.exists() || template.src.isDirectory()) { - throw new BadRequestException("couldn't extract template odt"); - } - } else if (zipEntry.getName().toLowerCase().endsWith(".docx")) { - //found a docx template inside the zip - template.type = DOCX; - template.src = Zip.zipEntryToFile(zipEntry, zipInputStream, template.tmpDir, "tmpl.docx"); - if (!template.src.exists() || template.src.isDirectory()) { - throw new BadRequestException("couldn't extract template docx"); - } - } else if (zipEntry.getName().toLowerCase().endsWith(".json")) { - //the json data the template is going to be resolved with - int jsonSize = (int) zipEntry.getSize(); - byte[] jsonBuffer; - if (jsonSize > 0) { - jsonBuffer = new byte[jsonSize]; - IOUtils.read(zipInputStream, jsonBuffer); - } else { - jsonBuffer = IOUtils.toByteArray(zipInputStream); - } - template.data = Json.fromJson(jsonBuffer, Map.class); - } else { - //other assets that should be referenced in the json data - Zip.zipEntryToFile(zipEntry, zipInputStream, template.tmpDir, zipEntry.getName()); - } - } - }); - if (template.src == null) { - throw new BadRequestException("template not found inside the ZIP"); - } - if (template.data == null) { - template.data = new HashMap(); - } - return template; - } - } diff --git a/src/main/java/com/proxeus/document/TemplateFormatter.java b/src/main/java/com/proxeus/document/TemplateFormatter.java new file mode 100644 index 0000000..a54fe3a --- /dev/null +++ b/src/main/java/com/proxeus/document/TemplateFormatter.java @@ -0,0 +1,10 @@ +package com.proxeus.document; + +import com.proxeus.office.libre.exe.Extension; + +import java.io.File; + +public interface TemplateFormatter { + String Convert(File src, File dst, String format, boolean restart) throws Exception; + Extension getExtension(String os); +} diff --git a/src/main/java/com/proxeus/document/docx/DOCXCompiler.java b/src/main/java/com/proxeus/document/docx/DOCXCompiler.java index f5394b5..7b9da6e 100644 --- a/src/main/java/com/proxeus/document/docx/DOCXCompiler.java +++ b/src/main/java/com/proxeus/document/docx/DOCXCompiler.java @@ -1,22 +1,27 @@ package com.proxeus.document.docx; -import com.proxeus.compiler.jtwig.MyJTwigCompiler; -import com.proxeus.document.DocumentCompilerIF; +import com.proxeus.document.DocumentCompiler; import com.proxeus.document.FileResult; import com.proxeus.document.Template; import com.proxeus.error.NotImplementedException; import com.proxeus.office.microsoft.MicrosoftOfficeAssistant; +import com.proxeus.xml.template.TemplateHandlerFactory; import java.util.Set; -public class DOCXCompiler implements DocumentCompilerIF { - private MyJTwigCompiler compiler; +/** + * This is a placeholder. + */ +public class DOCXCompiler implements DocumentCompiler { private MicrosoftOfficeAssistant microsoftOfficeAssistant; + private TemplateHandlerFactory templateHandlerFactory; - public DOCXCompiler(String cacheFolder, MyJTwigCompiler compiler, MicrosoftOfficeAssistant msAssistant) throws Exception { + public DOCXCompiler(String cacheFolder, MicrosoftOfficeAssistant msAssistant, TemplateHandlerFactory templateHandlerFactory) throws Exception { this.microsoftOfficeAssistant = msAssistant; - this.compiler = compiler; - //TODO impl. if demanded + this.templateHandlerFactory = templateHandlerFactory; + + //This is just a skeleton. Code to be implemented as required. + throw new NotImplementedException("DOCXCompiler not implemented"); } public FileResult Compile(Template template) throws Exception { diff --git a/src/main/java/com/proxeus/document/odt/ODTCompileRunnable.java b/src/main/java/com/proxeus/document/odt/ODTCompileRunnable.java deleted file mode 100644 index f09be5a..0000000 --- a/src/main/java/com/proxeus/document/odt/ODTCompileRunnable.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.proxeus.document.odt; - -import com.proxeus.compiler.jtwig.MyJTwigCompiler; -import com.proxeus.xml.Compiled; -import com.proxeus.xml.Node; -import com.proxeus.xml.XmlTemplateHandler; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.util.Map; -import java.util.Queue; - -/** - * ODTCompileRunnable runs the actual compilation async. - */ -public class ODTCompileRunnable implements Runnable { - private File xmlFile; - private XmlTemplateHandler xml; - private Map data; - private MyJTwigCompiler compiler; - private Queue exceptions; - - public ODTCompileRunnable(MyJTwigCompiler compiler, File xmlFile, XmlTemplateHandler xml, Map data, Queue exceptions){ - this.compiler = compiler; - //copy data as it will be executed async - this.data = data; - //this is not going to be used anymore by the main thread - this.xml = xml; - //this is going to be used when the task is finished - this.xmlFile = xmlFile; - this.exceptions = exceptions; - } - - public void run() { - try(FileOutputStream fos = new FileOutputStream(xmlFile)){ - if(xml.containsCode()){ - xml.fixCodeStructures(); - Node rootNodeContainingCode = xml.getRootNodeContainingCode(); - if (rootNodeContainingCode != null) { - //need to compile - InputStream forCompilation = rootNodeContainingCode.toInputStream(xml.getCharset()); - Compiled compiled = new Compiled(); - compiler.Compile(forCompilation, data, compiled.getOutputStream(), xml.getCharset()); - rootNodeContainingCode.replaceWith(compiled); - } - } - xml.toOutputStream(fos); - fos.flush(); - xml.free(); - xmlFile = null; - xml = null; - data = null; - exceptions = null; - } catch (Exception e) { - exceptions.offer(e); - } - } -} \ No newline at end of file diff --git a/src/main/java/com/proxeus/document/odt/ODTCompiler.java b/src/main/java/com/proxeus/document/odt/ODTCompiler.java index 84212b9..49f680d 100644 --- a/src/main/java/com/proxeus/document/odt/ODTCompiler.java +++ b/src/main/java/com/proxeus/document/odt/ODTCompiler.java @@ -1,52 +1,50 @@ package com.proxeus.document.odt; -import com.proxeus.compiler.jtwig.MyJTwigCompiler; -import com.proxeus.document.DocumentCompilerIF; -import com.proxeus.document.FileResult; -import com.proxeus.document.FontInstaller; -import com.proxeus.document.Template; -import com.proxeus.error.CompilationException; -import com.proxeus.error.InternalException; -import com.proxeus.error.UnavailableException; -import com.proxeus.office.libre.LibreOfficeAssistant; +import com.proxeus.document.*; +import com.proxeus.document.odt.img.ImageVarProcessor; +import com.proxeus.util.zip.EntryFileFilter; +import com.proxeus.util.zip.Zip; import com.proxeus.xml.Config; -import com.proxeus.xml.VarParser; - +import com.proxeus.xml.template.*; import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; +import org.apache.log4j.Logger; import java.io.File; -import java.io.FileOutputStream; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.util.Enumeration; +import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; -import static com.proxeus.document.odt.ODTContext.CONTENT_XML; +import static com.proxeus.document.odt.ODTRenderer.CONTENT_XML; +import static com.proxeus.document.odt.ODTRenderer.STYLE_XML; /** * ODTCompiler implements the actual odt specifics to compile it and convert it to the requested format. * It makes it possible to parse the vars only and it can print errors readable in the ODT. */ -public class ODTCompiler implements DocumentCompilerIF { +public class ODTCompiler implements DocumentCompiler { + private Logger log = Logger.getLogger(this.getClass()); + //only used for error public final static Charset UTF_8 = StandardCharsets.UTF_8; private File cacheDir; private final FontInstaller fontInstaller; - private ODTReadableErrorHandler odtReadableRrrorHandler = new ODTReadableErrorHandler(); private Config conf; - private LibreOfficeAssistant libreOfficeAssistant; - private MyJTwigCompiler compiler; + private TemplateFormatter templateFormatter; + private TemplateHandlerFactory templateHandlerFactory; + private TemplateVarParserFactory templateVarParserFactory; + + public ODTCompiler(String cacheFolder, + TemplateFormatter templateFormatter, + TemplateHandlerFactory templateHandlerFactory, + TemplateVarParserFactory templateVarParserFactory) throws Exception { + this.templateFormatter = templateFormatter; + this.templateHandlerFactory = templateHandlerFactory; + this.templateVarParserFactory = templateVarParserFactory; - public ODTCompiler(String cacheFolder, MyJTwigCompiler compiler, LibreOfficeAssistant libreOfficeAssistant) throws Exception { - this.libreOfficeAssistant = libreOfficeAssistant; fontInstaller = new FontInstaller(); if (cacheFolder == null || cacheFolder.equals("")) { cacheFolder = "odtCache"; @@ -63,101 +61,47 @@ public ODTCompiler(String cacheFolder, MyJTwigCompiler compiler, LibreOfficeAssi * This is only useful if you provide a broken XML that can not be read anymore. */ conf.Fix_XMLTags = false; - /** - * Add tag names for removal around code. - * They will be removed if they wrap single code blocks only. - */ - conf.AddTagNamesForRemovalAroundCode("text:span", "text:p"); + /** * Make code placement meaningful in the document. */ conf.FixCodeByFindingTheNextCommonParent = true; + + + // TODO: Need to improve the parser to handle table rows, i.e. extending the block instead of splitting it. /** * Try to find more suitable nodes to wrap if possible. */ conf.AddTryToWrapXMLTagWithCode("for", "table:table-row"); - - this.compiler = compiler; } public FileResult Compile(Template template) throws Exception { - return compile(template, null); + return compile(template); } - public Set Vars(Template template, String varPrefix) throws Exception { - VarParser varParser = new VarParser(varPrefix); - compile(template, varParser); - return varParser.Vars(); + public Set Vars(Template template, String prefix) throws Exception { + TemplateVarParser varParser = templateVarParserFactory.newInstance(); + findVars(template, varParser); + Set result = varParser.getVars().stream().filter(Objects::nonNull).filter(var -> var.startsWith(prefix != null ? prefix : "")).collect(Collectors.toSet()); + return result; } - private FileResult compile(Template template, VarParser varParser) throws Exception { - ODTContext cfc = new ODTContext(template, varParser); - try { - cfc.extractAndCompile(conf, compiler); - } catch (CompilationException e) { - cfc.waitForImageTasksToFinish(); - if(template.embedError){ - return renderOdtError(cfc.template, e.getMessage(), cfc.template.tmpDir); - }else{ - throw e; + private void findVars(Template template, TemplateVarParser varParser) throws Exception { + ImageVarProcessor imageVarProcessor = new ImageVarProcessor(varParser); + TemplateVarProcessor templateVarProcessor = new TemplateVarProcessor(varParser); + Zip.extract(template.getSrc(), (entry, zf) -> { + if (entry.getName().endsWith(CONTENT_XML) || entry.getName().endsWith(STYLE_XML)) { + TemplateHandler xml = templateHandlerFactory.newInstance( + imageVarProcessor, + templateVarProcessor + ); + xml.process(zf.getInputStream(entry)); } - } catch (Exception e) { - cfc.waitForImageTasksToFinish(); - throw e; - } - if (!cfc.readVarsOnly()) { - try{ - cfc.finish(); - }catch (Exception e){ - throw new InternalException("Couldn't finish up, error during pack to zip.", e); - } - try { - FileResult result = new FileResult(template); - result.target = new File(cfc.template.tmpDir, "final"); - result.template = cfc.template; - boolean newFontsInstalled = cfc.extractedFonts && fontInstaller.installDir(cfc.getFontsDir()); - result.contentType = libreOfficeAssistant.Convert(cfc.template.src, result.target, cfc.template.format, newFontsInstalled); - return result; - } catch (Exception e) { - cfc.waitForImageTasksToFinish(); - throw new UnavailableException("LibreOffice error during convert to " + cfc.template.format + " please try again."); - } - } - return null; + }); } - /** - * Printing error inside the document. - * TODO refactor string manipulation - */ - private FileResult renderOdtError(Template template, String error, File userTmpDir) throws Exception { - String contentXml = ""; - try (ZipFile zipFile = new ZipFile(template.src)) { - Enumeration entries = zipFile.entries(); - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - if (entry.getName().equalsIgnoreCase(CONTENT_XML)) { - contentXml = IOUtils.toString(zipFile.getInputStream(entry), UTF_8); - break; - } - } - } - contentXml = odtReadableRrrorHandler.setErrorMessage(contentXml, error); - File tmp = new File(userTmpDir, "odterror"); - try (FileOutputStream fos = new FileOutputStream(tmp)) { - fos.write(contentXml.getBytes(UTF_8)); - fos.flush(); - } - try (FileSystem fs = FileSystems.newFileSystem(template.src.toPath(), null)) { - Path fileInsideZipPath = fs.getPath("/" + CONTENT_XML); - Files.copy(tmp.toPath(), fileInsideZipPath, StandardCopyOption.REPLACE_EXISTING); - } - if (!tmp.delete()) { - System.out.println("renderOdtError tmp.delete() failed for " + tmp.getAbsolutePath()); - } - FileResult result = new FileResult(template); - result.target = new File(template.tmpDir, "error"); - result.contentType = libreOfficeAssistant.Convert(template.src, result.target, "pdf", false); - return result; + private FileResult compile(Template template) throws Exception { + ODTRenderer cfc = new ODTRenderer(template, templateHandlerFactory, templateFormatter); + return cfc.compile(conf, fontInstaller); } } diff --git a/src/main/java/com/proxeus/document/odt/ODTContext.java b/src/main/java/com/proxeus/document/odt/ODTContext.java deleted file mode 100644 index 26765d9..0000000 --- a/src/main/java/com/proxeus/document/odt/ODTContext.java +++ /dev/null @@ -1,317 +0,0 @@ -package com.proxeus.document.odt; - -import com.proxeus.compiler.jtwig.MyJTwigCompiler; -import com.proxeus.document.AssetFile; -import com.proxeus.document.Template; -import com.proxeus.document.odt.img.ImageAdjusterRunnable; -import com.proxeus.document.odt.img.ImageSettings; -import com.proxeus.error.CompilationException; -import com.proxeus.util.Eval; -import com.proxeus.util.zip.EntryFileFilter; -import com.proxeus.util.zip.Zip; -import com.proxeus.xml.Config; -import com.proxeus.xml.Element; -import com.proxeus.xml.Node; -import com.proxeus.xml.Tag; -import com.proxeus.xml.TagType; -import com.proxeus.xml.VarParser; -import com.proxeus.xml.XmlTemplateHandler; - -import org.apache.commons.io.FileUtils; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.NoSuchFileException; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -/** - * ODTContext takes away the complexity from ODTCompiler and the image handling - * by keeping the things that are needed from the beginning until the end here together. - */ -public class ODTContext { - public final static String CONTENT_XML = "content.xml"; - public final static String STYLE_XML = "styles.xml"; - public final static String META_XML = "meta.xml"; - public Template template; - public ExecutorService imgExecutor; - public ExecutorService compileExecutor; - public VarParser varParser; - public boolean extractedFonts; - public XmlTemplateHandler manifest = null; - public File manifestDest = null; - public List extractedFiles = new ArrayList<>(2); - public Queue assetFilesToInclude = new ConcurrentLinkedQueue<>(); - public Queue fileToRemoveFromZip = new ConcurrentLinkedQueue<>(); - public Queue compileExceptions = new ConcurrentLinkedQueue<>(); - - public ODTContext(Template template, VarParser varParser) { - this.template = template; - this.varParser = varParser; - if (!readVarsOnly()) { - imgExecutor = Executors.newFixedThreadPool(4); - compileExecutor = Executors.newFixedThreadPool(2); - } - } - - public void extractAndCompile(Config conf, MyJTwigCompiler compiler) throws Exception { - Map dirsMade = new HashMap<>(4); - Zip.extract(template.src, new EntryFileFilter() { - public void next(ZipEntry entry, ZipFile zf) throws Exception { - if (entry.getName().startsWith("Fonts/")) { - extractedFonts = true; - File toExtract = new File(template.tmpDir, entry.getName()); - ensureDirExists(toExtract.getParentFile(), dirsMade); - FileUtils.copyToFile(zf.getInputStream(entry), toExtract); - } else if (!readVarsOnly() && entry.getName().equals("META-INF/manifest.xml")) { - manifest = new XmlTemplateHandler(conf, zf.getInputStream(entry), entry.getSize()); - manifestDest = new File(template.tmpDir, entry.getName()); - ensureDirExists(manifestDest.getParentFile(), dirsMade); - } else if (entry.getName().endsWith(CONTENT_XML) || entry.getName().endsWith(STYLE_XML)) { - File toExtract = null; - if (!readVarsOnly()) { - toExtract = new File(template.tmpDir, entry.getName()); - ensureDirExists(toExtract.getParentFile(), dirsMade); - } - XmlTemplateHandler xml = new XmlTemplateHandler(conf, zf.getInputStream(entry), entry.getSize()); - try { - checkForAssetFileReplacements(xml, entry); - } catch (Exception e) { - throw new CompilationException("error when replacing images", e); - } - if (readVarsOnly()) { - xml.findVars(varParser); - xml.free(); - } else { - extractedFiles.add(toExtract); - compileExecutor.submit(new ODTCompileRunnable(compiler, toExtract, xml, template.getDataCopy(), compileExceptions)); - } - } - } - }); - waitForCompileTasksToFinish(); - } - - public File getFontsDir(){ - return new File(template.tmpDir, "Fonts"); - } - - private void ensureDirExists(File dir, Map dirsMade){ - if(!dirsMade.containsKey(dir.getAbsolutePath())){ - dir.mkdirs(); - dirsMade.put(dir.getAbsolutePath(), true); - } - } - - private void waitForCompileTasksToFinish() throws Exception { - if (!readVarsOnly()) { - compileExecutor.shutdown(); - compileExecutor.awaitTermination(15, TimeUnit.SECONDS); - if(compileExceptions.size()>0){ - //at least one exception was thrown during compilation, throw the first one - //lets assume the first exception is accurate enough to help solving the issue - throw compileExceptions.poll(); - } - } - } - - public void waitForImageTasksToFinish() throws Exception { - if (!readVarsOnly()) { - imgExecutor.shutdown(); - imgExecutor.awaitTermination(15, TimeUnit.SECONDS); - } - } - - protected void processManifest() { - if (manifest != null) { - try { - List manifestFileEntries = manifest.findElementsByName("manifest:file-entry"); - ListIterator elementListIterator = manifestFileEntries.listIterator(); - for (AssetFile f : assetFilesToInclude) { - if (f.orgZipPath != null) { - while (elementListIterator.hasNext()) { - Element element = elementListIterator.next(); - if (element.toString().contains(f.orgZipPath)) { - element.remove();//remove from dom - elementListIterator.remove();//remove from this list - break; - } - } - } - } - List manifestMain = manifest.findElementsByName("manifest:manifest"); - if (manifestMain != null && manifestMain.size() > 0) { - for (AssetFile f : assetFilesToInclude) { - String newImgTag = ""; - ((Node) manifestMain.get(0)).addChild(new Node(new Tag(newImgTag, TagType.START_AND_END))); - } - } - FileOutputStream manifestOs = new FileOutputStream(manifestDest); - manifest.toOutputStream(manifestOs); - manifestOs.flush(); - manifestOs.close(); - manifest.free(); - manifest = null; - } catch (Exception e) { - //not important as libre will handle it with the repair feature - System.err.println("couldn't modify the manifest"); - } - } - } - - public void finish() throws Exception { - Set collectedEmbeddedObjects = new HashSet<>(); - try (FileSystem fs = FileSystems.newFileSystem(template.src.toPath(), null)) { - for (File newPath : extractedFiles) { - String zipPath = getZipPath(template.tmpDir, newPath.getAbsolutePath()); - try { - if (zipPath.startsWith(File.separator + "Object")) { - collectedEmbeddedObjects.add(zipPath.split(File.separator)[1]); - } - } catch (Exception e) { - e.printStackTrace(); - } - Files.move(newPath.toPath(), fs.getPath(zipPath), StandardCopyOption.REPLACE_EXISTING); - } - for (String embeddedCacheToDelete : collectedEmbeddedObjects) { - Zip.delete(fs.getPath("/ObjectReplacements/" + embeddedCacheToDelete)); - } - if (fileToRemoveFromZip != null && fileToRemoveFromZip.size() > 0) { - for (String toRemPath : fileToRemoveFromZip) { - Zip.delete(fs.getPath(toRemPath)); - } - } - waitForImageTasksToFinish(); - processManifest(); - insertManifest(fs); - includeAssets(fs); - } - } - - private void insertManifest(FileSystem fs) { - try { - Files.move(manifestDest.toPath(), fs.getPath(getZipPath(template.tmpDir, manifestDest.getAbsolutePath())), StandardCopyOption.REPLACE_EXISTING); - } catch (Exception e) { - //not important as it will work without it - } - } - - private void includeAssets(FileSystem fs) throws IOException { - for (AssetFile f : assetFilesToInclude) { - if (!f.dst.exists()) { - //looks like it as been already moved to the zip - continue; - } - Path insideZip = fs.getPath(f.newZipPath); - try { - Files.move(f.dst.toPath(), insideZip, StandardCopyOption.REPLACE_EXISTING); - } catch (NoSuchFileException nsf) { - Files.createDirectories(insideZip.getParent()); - Files.move(f.dst.toPath(), insideZip, StandardCopyOption.REPLACE_EXISTING); - } - } - } - - private static String getZipPath(File userTmpDir, String path) { - String extractedDir = userTmpDir.getName() + File.separator; - return File.separator + path.substring(path.lastIndexOf(extractedDir) + extractedDir.length()); - } - - /** - * styles: - *

- * - * - * - *

- *

- * - * - * - */ - private void checkForAssetFileReplacements(XmlTemplateHandler xml, ZipEntry entry) throws Exception { - String xmlDirPath = Zip.dirPath(entry.getName()); - List imgElements = xml.findElementsByName("draw:frame"); - if (imgElements != null && imgElements.size() > 0) { - for (Element imgEle : imgElements) { - List drwImgs = imgEle.findElementByName("draw:image"); - if (drwImgs != null && drwImgs.size() > 0) { - Element drwImg = drwImgs.get(0); - assetFileReplacement(imgEle, drwImg, xmlDirPath); - } - } - } - } - - /** - * Do the necessary changes on the ODT's XML and execute the image adjuster thread. - * If we are not just looking for vars and if a valid var was specified in the ODT for this very img element. - * - * @param imgEle img element - * @param drwImg child element of img element - * @param xmlDirPath inside the zip - */ - public void assetFileReplacement(Element imgEle, Element drwImg, String xmlDirPath) throws Exception { - String varWithOptions = imgEle.attr("draw:name"); - if (varWithOptions == null || !(varWithOptions = varWithOptions.trim()).startsWith("{{") || !varWithOptions.endsWith("}}")) { - //continue as there is no valid var expression and therefore nothing for us to do on this image tag - return; - } - //take away the expression >{{< * >}}< - varWithOptions = varWithOptions.substring(2, varWithOptions.length() - 2).trim(); - ImageSettings imgStngs = new ImageSettings( - xmlDirPath, - drwImg.attr("xlink:href"), - varWithOptions, - imgEle.attr("svg:width"), - imgEle.attr("svg:height"), - this - ); - if (readVarsOnly()) { - //we want to read the var only so parse it and continue - //it is important to do it after new ImageSettings to parse away the image options - varParser.Parse("{{"+imgStngs.varOnly+"}}"); - return; - } - imgEle.attr("draw:name", "img" + System.nanoTime()); - - if (imgStngs.readyToBeExecuted()) { - imgStngs.touchFile(); - //resolve the variable synchronously to the image settings so it can be executed asynchronously - imgStngs.localRemoteOrEmbeddedFileObject = Eval.me(imgStngs.varOnly, template.data); - if(imgStngs.localRemoteOrEmbeddedFileObject != null){ - //the adjusted image will be always a png - drwImg.attr("loext:mime-type", "image/png"); - //make sure it is embedded by forcing the path Pictures/imageSettingsID - //this path must be relative - //if there is an embedded object like Object 1/Pictures.., the path in the content.xml is still Pictures/.. but not in the root manifest - drwImg.attr("xlink:href", "Pictures/" + imgStngs.ID()); - imgExecutor.submit(new ImageAdjusterRunnable(imgStngs)); - } - } - } - - public boolean readVarsOnly() { - return varParser != null; - } -} \ No newline at end of file diff --git a/src/main/java/com/proxeus/document/odt/ODTManifestProcessor.java b/src/main/java/com/proxeus/document/odt/ODTManifestProcessor.java new file mode 100644 index 0000000..d43cbfd --- /dev/null +++ b/src/main/java/com/proxeus/document/odt/ODTManifestProcessor.java @@ -0,0 +1,122 @@ +package com.proxeus.document.odt; + +import com.google.common.base.Strings; +import com.proxeus.document.AssetFile; +import com.proxeus.xml.processor.XMLEventProcessor; +import org.apache.log4j.Logger; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLEventFactory; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.util.Arrays; +import java.util.List; +import java.util.Queue; + +public class ODTManifestProcessor implements XMLEventProcessor { + private Logger log = Logger.getLogger(this.getClass()); + + static private String MANIFEST_NAMESPACE = "urn:oasis:names:tc:opendocument:xmlns:manifest:1.0"; + static private String MANIFEST_PREFIX = "manifest"; + static private QName MANIFEST = new QName(MANIFEST_NAMESPACE, "manifest", MANIFEST_PREFIX); + static private QName FILE_ENTRY = new QName(MANIFEST_NAMESPACE, "file-entry", MANIFEST_PREFIX); + static private QName FULL_PATH = new QName(MANIFEST_NAMESPACE, "full-path", MANIFEST_PREFIX); + static private QName MEDIA_TYPE = new QName(MANIFEST_NAMESPACE, "media-type", MANIFEST_PREFIX); + static private XMLEventFactory eventFactory = XMLEventFactory.newInstance(); + + + private Queue assetFiles; + private boolean deleteFileEntry = false; + + ODTManifestProcessor(Queue assetFiles) { + this.assetFiles = assetFiles; + } + + @Override + public void process(XMLEventReader reader, XMLEventWriter writer) throws XMLStreamException, IllegalStateException { + try { + while (reader.hasNext()) { + XMLEvent event = reader.nextEvent(); + switch (event.getEventType()) { + case XMLEvent.START_DOCUMENT: + writer.add(event); + writer.add(eventFactory.createCharacters(System.lineSeparator())); + break; + case XMLEvent.START_ELEMENT: + StartElement s = event.asStartElement(); + process(s, writer); + break; + case XMLEvent.END_ELEMENT: + EndElement e = event.asEndElement(); + process(e, writer); + break; + default: + if(!deleteFileEntry){ + writer.add(event); + } + } + } + } catch (Exception e) { + //not important as LibreOffice will handle it with the repair feature + log.info("couldn't modify the manifest", e); + } + } + + private void process(StartElement s, XMLEventWriter writer) throws XMLStreamException { + if (!FILE_ENTRY.equals(s.getName())) { + writer.add(s); + return; + } + + Attribute a = s.getAttributeByName(FULL_PATH); + if (a == null) { + writer.add(s); + return; + } + + String fullPath = a.getValue(); + + for (AssetFile file : assetFiles) { + if (Strings.isNullOrEmpty(file.orgZipPath)) { + continue; + } + if (fullPath.contains(file.orgZipPath)) { + // We filter out file entries with matching path. + deleteFileEntry = true; + return; + } + } + + writer.add(s); + } + + private void process(EndElement e, XMLEventWriter writer) throws XMLStreamException { + if (FILE_ENTRY.equals(e.getName()) && deleteFileEntry) { + deleteFileEntry = false; + return; + } + + if (!MANIFEST.equals(e.getName())) { + writer.add(e); + return; + } + + for (AssetFile file : assetFiles) { + List attributes = Arrays.asList( + eventFactory.createAttribute(FULL_PATH, file.newZipPath), + eventFactory.createAttribute(MEDIA_TYPE, "image/png") + ); + + writer.add(eventFactory.createStartElement(FILE_ENTRY, attributes.iterator(), null)); + writer.add(eventFactory.createEndElement(FILE_ENTRY, null)); + } + + writer.add(eventFactory.createCharacters(System.lineSeparator())); + writer.add(e); + } +} diff --git a/src/main/java/com/proxeus/document/odt/ODTReadableErrorHandler.java b/src/main/java/com/proxeus/document/odt/ODTReadableErrorHandler.java index be7eb40..a371c04 100644 --- a/src/main/java/com/proxeus/document/odt/ODTReadableErrorHandler.java +++ b/src/main/java/com/proxeus/document/odt/ODTReadableErrorHandler.java @@ -7,7 +7,6 @@ /** * This class helps to make complicated errors inside an ODT document visible. This way it is easier to track the mistakes and fix them. - * TODO improve the performance and memory usage by avoiding string modifications as much as possible */ public class ODTReadableErrorHandler { private String errFrame; diff --git a/src/main/java/com/proxeus/document/odt/ODTRenderer.java b/src/main/java/com/proxeus/document/odt/ODTRenderer.java new file mode 100644 index 0000000..47f9721 --- /dev/null +++ b/src/main/java/com/proxeus/document/odt/ODTRenderer.java @@ -0,0 +1,282 @@ +package com.proxeus.document.odt; + +import com.proxeus.document.*; +import com.proxeus.document.odt.img.ImageAdjustProcessorFactory; +import com.proxeus.error.CompilationException; +import com.proxeus.error.InternalException; +import com.proxeus.error.UnavailableException; +import com.proxeus.util.zip.EntryFileFilter; +import com.proxeus.util.zip.Zip; +import com.proxeus.xml.Config; +import com.proxeus.xml.template.CleanEmptyElementProcessor; +import com.proxeus.xml.template.TemplateHandler; +import com.proxeus.xml.template.TemplateHandlerFactory; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.log4j.Logger; + +import javax.xml.namespace.QName; +import java.io.*; +import java.nio.file.FileSystem; +import java.nio.file.*; +import java.util.*; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import static java.nio.charset.StandardCharsets.UTF_8; + +/** + * ODTRenderer takes away the complexity from ODTCompiler and the image handling + * by keeping the things that are needed from the beginning until the end here together. + */ +public class ODTRenderer { + private Logger log = Logger.getLogger(this.getClass()); + + private static String TEXT = "urn:oasis:names:tc:opendocument:xmlns:text:1.0"; + private static QName TEXT_SPAN = new QName(TEXT, "span"); + + private static List EMPTY_XML_ELEMENT_TO_REMOVE = Arrays.asList(TEXT_SPAN); + + final static String CONTENT_XML = "content.xml"; + final static String STYLE_XML = "styles.xml"; + public Template template; + private boolean extractedFonts; + private TemplateHandler manifest = null; + private File manifestDest = null; + private ByteArrayOutputStream manifestContent = null; + private Queue fileToRemoveFromZip = new ConcurrentLinkedQueue<>(); + + + private ImageAdjustProcessorFactory imageAdjuster; + private TemplateHandlerFactory templateHandlerFactory; + + private TemplateFormatter templateFormatter; + + ODTRenderer(Template template, TemplateHandlerFactory templateHandlerFactory, TemplateFormatter templateFormatter) { + this.template = template; + this.templateHandlerFactory = templateHandlerFactory; + this.templateFormatter = templateFormatter; + this.imageAdjuster = new ImageAdjustProcessorFactory(template.getTmpDir(), template.getDataCopy()); + } + + + protected FileResult compile(Config conf, FontInstaller fontInstaller) throws Exception { + try { + List extractedFiles = extractAndCompile(conf); + assembleZipFile(extractedFiles); + } catch (CompilationException e) { + if (template.isEmbedError()) { + return renderOdtError(template, e.getMessage(), template.getTmpDir()); + } else { + throw e; + } + } + return format(fontInstaller); + } + + + private List extractAndCompile(Config conf) throws Exception { + ExecutorService compileExecutor = Executors.newFixedThreadPool(2); + List extractedFiles = new ArrayList<>(2); + Queue compileExceptions = new ConcurrentLinkedQueue<>(); + try { + Zip.extract(template.getSrc(), (entry, zf) -> { + if (entry.getName().startsWith("Fonts/")) { + extractedFonts = true; + File toExtract = new File(template.getTmpDir(), entry.getName()); + toExtract.getParentFile().mkdirs(); + FileUtils.copyToFile(zf.getInputStream(entry), toExtract); + } else if (entry.getName().equals("META-INF/manifest.xml")) { + manifestDest = new File(template.getTmpDir(), entry.getName()); + manifestDest.getParentFile().mkdirs(); + manifestContent = new ByteArrayOutputStream(); + IOUtils.copy(zf.getInputStream(entry), manifestContent); + } else if (entry.getName().endsWith(CONTENT_XML) || entry.getName().endsWith(STYLE_XML)) { + TemplateHandler xml = templateHandlerFactory.newInstance( + new CleanEmptyElementProcessor(EMPTY_XML_ELEMENT_TO_REMOVE), + imageAdjuster.newInstance(entry.getName()) + ); + xml.process(zf.getInputStream(entry)); + + + File toExtract = new File(template.getTmpDir(), entry.getName()); + toExtract.getParentFile().mkdirs(); + extractedFiles.add(toExtract); + + compileExecutor.submit(() -> { + try { + FileOutputStream output = new FileOutputStream(toExtract); + xml.render(output, template.getDataCopy()); + output.flush(); + } catch (Exception e) { + compileExceptions.offer(e); + } + }); + } + }); + + compileExecutor.shutdown(); + compileExecutor.awaitTermination(15, TimeUnit.SECONDS); + if (compileExceptions.size() > 0) { + //at least one exception was thrown during compilation, throw the first one + //lets assume the first exception is accurate enough to help solving the issue + throw compileExceptions.poll(); + } + } catch (Exception e) { + waitForImageTasksToFinish(); + throw e; + } + return extractedFiles; + } + + void assembleZipFile(List extractedFiles) throws Exception { + Set collectedEmbeddedObjects = new HashSet<>(); + try (FileSystem fs = FileSystems.newFileSystem(template.getSrc().toPath(), null)) { + for (File newPath : extractedFiles) { + String zipPath = getZipPath(template.getTmpDir(), newPath.getAbsolutePath()); + try { + if (zipPath.startsWith(File.separator + "Object")) { + collectedEmbeddedObjects.add(zipPath.split(File.separator)[1]); + } + } catch (Exception e) { + e.printStackTrace(); + } + Files.move(newPath.toPath(), fs.getPath(zipPath), StandardCopyOption.REPLACE_EXISTING); + } + for (String embeddedCacheToDelete : collectedEmbeddedObjects) { + Zip.delete(fs.getPath("/ObjectReplacements/" + embeddedCacheToDelete)); + } + if (fileToRemoveFromZip != null && fileToRemoveFromZip.size() > 0) { + for (String toRemPath : fileToRemoveFromZip) { + Zip.delete(fs.getPath(toRemPath)); + } + } + + Queue assetFiles = waitForImageTasksToFinish(); + processManifest(assetFiles); + insertManifest(fs); + includeAssets(assetFiles, fs); + } catch (Exception e) { + throw new InternalException("Couldn't finish up, error during pack to zip.", e); + } + } + + private FileResult format(FontInstaller fontInstaller) throws UnavailableException { + try { + FileResult result = new FileResult(template); + result.target = new File(template.getTmpDir(), "final"); + result.template = template; + boolean newFontsInstalled = extractedFonts && fontInstaller.installDir(getFontsDir()); + result.contentType = templateFormatter.Convert(template.getSrc(), result.target, template.getFormat(), newFontsInstalled); + return result; + } catch (Exception e) { + e.printStackTrace(); + throw new UnavailableException("LibreOffice error during convert to " + template.getFormat() + ": " + e.getMessage()); + } + } + + File getFontsDir() { + return new File(template.getTmpDir(), "Fonts"); + } + + Queue waitForImageTasksToFinish() throws Exception { + ImageAdjustProcessorFactory.Result result = imageAdjuster.finish(); + if (result.getExceptions().size() > 0) { + Exception e = result.getExceptions().poll(); + if (e != null) { + throw e; + } + } + return result.getAssetFiles(); + } + + private void processManifest(Queue assetFiles) throws Exception { + try { + if (manifestContent == null) { + return; + } + + TemplateHandler manifest = templateHandlerFactory.newInstance( + new ODTManifestProcessor(assetFiles) + ); + manifest.process(new ByteArrayInputStream(manifestContent.toByteArray())); + + + FileOutputStream output = new FileOutputStream(manifestDest); + + manifest.render(output, Collections.emptyMap()); + } catch (Exception e) { + throw e; + } + } + + + private void insertManifest(FileSystem fs) { + try { + Files.move(manifestDest.toPath(), fs.getPath(getZipPath(template.getTmpDir(), manifestDest.getAbsolutePath())), StandardCopyOption.REPLACE_EXISTING); + } catch (Exception e) { + log.error("Could not insert manifest", e); + } + } + + private void includeAssets(Queue assetFiles, FileSystem fs) throws IOException { + for (AssetFile f : assetFiles) { + if (!f.dst.exists()) { + //looks like it as been already moved to the zip + continue; + } + Path insideZip = fs.getPath(f.newZipPath); + try { + Files.move(f.dst.toPath(), insideZip, StandardCopyOption.REPLACE_EXISTING); + } catch (NoSuchFileException nsf) { + Files.createDirectories(insideZip.getParent()); + Files.move(f.dst.toPath(), insideZip, StandardCopyOption.REPLACE_EXISTING); + } + } + } + + private static String getZipPath(File userTmpDir, String path) { + String extractedDir = userTmpDir.getName() + File.separator; + return File.separator + path.substring(path.lastIndexOf(extractedDir) + extractedDir.length()); + } + + /** + * Printing error inside the document. + */ + private FileResult renderOdtError(Template template, String error, File userTmpDir) throws Exception { + String contentXml = ""; + try (ZipFile zipFile = new ZipFile(template.getSrc())) { + Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + if (CONTENT_XML.equalsIgnoreCase(entry.getName())) { + contentXml = IOUtils.toString(zipFile.getInputStream(entry), UTF_8); + break; + } + } + } + + ODTReadableErrorHandler odtReadableErrorHandler = new ODTReadableErrorHandler(); + contentXml = odtReadableErrorHandler.setErrorMessage(contentXml, error); + File tmp = new File(userTmpDir, "odterror"); + try (FileOutputStream fos = new FileOutputStream(tmp)) { + fos.write(contentXml.getBytes(UTF_8)); + fos.flush(); + } + try (FileSystem fs = FileSystems.newFileSystem(template.getSrc().toPath(), null)) { + Path fileInsideZipPath = fs.getPath("/" + CONTENT_XML); + Files.copy(tmp.toPath(), fileInsideZipPath, StandardCopyOption.REPLACE_EXISTING); + } + if (!tmp.delete()) { + log.error("renderOdtError tmp.delete() failed for " + tmp.getAbsolutePath()); + } + FileResult result = new FileResult(template); + result.target = new File(template.getTmpDir(), "error"); + result.contentType = templateFormatter.Convert(template.getSrc(), result.target, "pdf", false); + return result; + } +} \ No newline at end of file diff --git a/src/main/java/com/proxeus/document/odt/img/ImageAdjustProcessorFactory.java b/src/main/java/com/proxeus/document/odt/img/ImageAdjustProcessorFactory.java new file mode 100644 index 0000000..bd38167 --- /dev/null +++ b/src/main/java/com/proxeus/document/odt/img/ImageAdjustProcessorFactory.java @@ -0,0 +1,248 @@ +package com.proxeus.document.odt.img; + +import com.proxeus.document.AssetFile; +import com.proxeus.util.Eval; +import com.proxeus.util.zip.Zip; +import com.proxeus.xml.processor.XMLEventProcessor; +import org.apache.log4j.Logger; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLEventFactory; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.io.File; +import java.util.*; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +public class ImageAdjustProcessorFactory { + + private final static String DRAW = "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"; + private final static QName DRAW_FRAME = new QName(DRAW, "frame", "draw"); + private final static QName DRAW_IMAGE = new QName(DRAW, "image", "draw"); + private final static QName DRAW_NAME = new QName(DRAW, "name", "draw"); + private final static String XLINK = "http://www.w3.org/1999/xlink"; + private final static QName XLINK_HREF = new QName(XLINK, "href", "xlink"); + private final static String SVG = "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"; + private final static QName SVG_WIDTH = new QName(SVG, "width", "svg"); + private final static QName SVG_HEIGHT = new QName(SVG, "height", "svg"); + private final static String LOEXT = "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"; + private final static QName LOEXT_MIMETYPE = new QName(LOEXT, "mime-type", "loext"); + + private Map data; + private ExecutorService imgExecutor = Executors.newFixedThreadPool(4); + private Queue assetFiles = new ConcurrentLinkedQueue<>(); + private Queue exceptions = new ConcurrentLinkedQueue<>(); + private File tmpDir; + private XMLEventFactory eventFactory = XMLEventFactory.newInstance(); + + public ImageAdjustProcessorFactory(File tmpDir, Map data) { + this.data = data; + this.tmpDir = tmpDir; + } + + public XMLEventProcessor newInstance(String entryName) { + return new ImageAdjustProcessor(entryName); + } + + public class ImageAdjustProcessor implements XMLEventProcessor { + private Logger log = Logger.getLogger(this.getClass()); + + private String entryName; + + ImageAdjustProcessor(String entryName) { + this.entryName = entryName; + } + + /** + * styles: + *

+ * + * + * + *

+ *

+ * + * + * + */ + @Override + public void process(XMLEventReader reader, XMLEventWriter writer) throws XMLStreamException, IllegalStateException { + String xmlDirPath = Zip.dirPath(entryName); + Queue frameEvents = new LinkedList<>(); + + while (reader.hasNext()) { + XMLEvent event = reader.nextEvent(); + switch (event.getEventType()) { + case XMLEvent.START_ELEMENT: + StartElement start = event.asStartElement(); + if (start.getName().equals(DRAW_FRAME)) { + frameEvents.add(start); + continue; + } + if (start.getName().equals(DRAW_IMAGE)) { + frameEvents.add(start); + continue; + } + writer.add(start); + continue; + case XMLEvent.END_ELEMENT: + EndElement end = event.asEndElement(); + if (end.getName().equals(DRAW_IMAGE)) { + frameEvents.add(end); + continue; + } + if (end.getName().equals(DRAW_FRAME)) { + frameEvents.add(end); + for (XMLEvent e : assetFileReplacement(frameEvents, xmlDirPath)) { + writer.add(e); + } + frameEvents.clear(); + continue; + } + writer.add(end); + continue; + default: + writer.add(event); + } + } + } + + /** + * Do the necessary changes on the ODT's XML and execute the image adjuster thread. + * If we are not just looking for vars and if a valid var was specified in the ODT for this very img element. + * + * @param frame img element + * @param image child element of img element + * @param xmlDirPath inside the zip + */ + Queue assetFileReplacement(Queue frameEvents, String xmlDirPath) { + StartElement frame = frameEvents.peek().asStartElement(); + + String varWithOptions = attr(frame, DRAW_NAME); + if (!(varWithOptions.startsWith("{{") && varWithOptions.endsWith("}}"))) { + //continue as there is no valid var expression and therefore nothing for us to do on this image tag + return frameEvents; + } + // Consume the frame start element + frameEvents.poll(); + + Queue result = new LinkedList<>(); + + result.add(update(frame, Arrays.asList( + eventFactory.createAttribute(DRAW_NAME, "img" + System.nanoTime())) + )); + + //take away the expression >{{< * >}}< + varWithOptions = varWithOptions.substring(2, varWithOptions.length() - 2).trim(); + StartElement image = frameEvents.peek().asStartElement(); + ImageSettings imgStngs = new ImageSettings( + xmlDirPath, + attr(image, XLINK_HREF), + varWithOptions, + attr(frame, SVG_WIDTH), + attr(frame, SVG_HEIGHT), + tmpDir, + assetFiles + ); + + if (!imgStngs.readyToBeExecuted()) { + result.addAll(frameEvents); + return result; + } + + try { + imgStngs.touchFile(); + } catch (Exception e) { + exceptions.offer(e); + result.addAll(frameEvents); + return result; + } + + //resolve the variable synchronously to the image settings so it can be executed asynchronously + imgStngs.localRemoteOrEmbeddedFileObject = Eval.me(imgStngs.varOnly, data); + + if (imgStngs.localRemoteOrEmbeddedFileObject == null) { + result.addAll(frameEvents); + return result; + } + + // consume the image start event + frameEvents.poll(); + //the adjusted image will be always a png + image = update(image,Arrays.asList( + //the adjusted image will be always a png + eventFactory.createAttribute(LOEXT_MIMETYPE, "image/png"), + //make sure it is embedded by forcing the path Pictures/imageSettingsID + //this path must be relative + //if there is an embedded object like Object 1/Pictures.., the path in the content.xml is still Pictures/.. but not in the root manifest + eventFactory.createAttribute(XLINK_HREF, "Pictures/" + imgStngs.ID()) + )); + + result.add(image); + result.addAll(frameEvents); + + imgExecutor.submit(new ImageAdjusterRunnable(imgStngs, exceptions)); + + return result; + } + } + + private String attr(StartElement start, QName name) { + Attribute attribute = start.getAttributeByName(name); + if (attribute == null) { + return ""; + } + return attribute.getValue().trim(); + } + + private StartElement update(StartElement start, List updatedAttributes) { + Map attributes = new HashMap<>(); + Iterator it = start.getAttributes(); + while (it.hasNext()) { + Attribute a = (Attribute) it.next(); + attributes.put(a.getName(), a); + } + for(Attribute updated : updatedAttributes){ + attributes.put(updated.getName(), updated); + } + + return eventFactory.createStartElement(start.getName(), attributes.values().iterator(), null); + } + + public Result finish() throws Exception { + imgExecutor.shutdown(); + imgExecutor.awaitTermination(15, TimeUnit.SECONDS); + return new Result(assetFiles, exceptions); + } + + + public class Result { + + private Queue assetFiles; + private Queue exceptions; + + Result(Queue assetFiles, Queue exceptions) { + this.assetFiles = assetFiles; + this.exceptions = exceptions; + } + + public Queue getAssetFiles() { + return assetFiles; + } + + public Queue getExceptions() { + return exceptions; + } + } + +} diff --git a/src/main/java/com/proxeus/document/odt/img/ImageAdjusterRunnable.java b/src/main/java/com/proxeus/document/odt/img/ImageAdjusterRunnable.java index dc6e626..197a392 100644 --- a/src/main/java/com/proxeus/document/odt/img/ImageAdjusterRunnable.java +++ b/src/main/java/com/proxeus/document/odt/img/ImageAdjusterRunnable.java @@ -2,26 +2,33 @@ import com.proxeus.document.AssetFile; import com.proxeus.util.Image; +import org.apache.log4j.Logger; + +import java.util.Queue; /** * ImageAdjusterRunnable helps us to gain performance with the image manipulations as it can run independently from the main thread. * Until the main thread is ready to pack the files back to the ODT. */ public class ImageAdjusterRunnable implements Runnable { + private Logger log = Logger.getLogger(this.getClass()); + private ImageSettings imageSettings; + private Queue exceptions; - public ImageAdjusterRunnable(ImageSettings imageSettings) { + public ImageAdjusterRunnable(ImageSettings imageSettings, Queue exceptions) { this.imageSettings = imageSettings; + this.exceptions = exceptions; } public void run() { try { - AssetFile assetFile = AssetFile.find(imageSettings.localRemoteOrEmbeddedFileObject, imageSettings.cfc.template.tmpDir); + AssetFile assetFile = AssetFile.find(imageSettings.localRemoteOrEmbeddedFileObject, imageSettings.tmpDir); if (assetFile != null) { assetFile.dst = imageSettings.dst; assetFile.orgZipPath = imageSettings.refFileName; assetFile.newZipPath = "/" + joinZipPath(imageSettings.xmlDirPath, "Pictures/" + imageSettings.ID()); - if(imageSettings.cfc.assetFilesToInclude.offer(assetFile)){ + if(imageSettings.assetFilesToInclude.offer(assetFile)){ Image.adjustToFitToRatio( assetFile.src, imageSettings.dst, @@ -33,11 +40,20 @@ public void run() { } } } catch (Exception e) { - System.err.println("couldn't adjust the image to the provided container"); e.printStackTrace(); + System.err.println("couldn't adjust the image to the provided container"); + exceptions.offer(e); } } + protected ImageSettings getSettings() { + return this.imageSettings; + } + + protected Queue getExceptions() { + return this.exceptions; + } + private static String joinZipPath(String a, String b) { if (a.length() == 0) { return b; diff --git a/src/main/java/com/proxeus/document/odt/img/ImageSettings.java b/src/main/java/com/proxeus/document/odt/img/ImageSettings.java index 6592ae4..443cd20 100644 --- a/src/main/java/com/proxeus/document/odt/img/ImageSettings.java +++ b/src/main/java/com/proxeus/document/odt/img/ImageSettings.java @@ -1,11 +1,11 @@ package com.proxeus.document.odt.img; -import com.proxeus.document.odt.ODTContext; - +import com.proxeus.document.AssetFile; import org.apache.commons.codec.binary.Hex; import java.io.File; import java.io.FileOutputStream; +import java.util.Queue; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -37,12 +37,14 @@ public class ImageSettings { public Object localRemoteOrEmbeddedFileObject; private final static Pattern imageOptionsRegex = Pattern.compile("(.*)\\[([^\\[\\]]*)\\]"); private boolean containerDimensionSet = false; - protected ODTContext cfc; + protected File tmpDir; + protected Queue assetFilesToInclude; - public ImageSettings(String xmlDirPath, String refFileName, String varWithOptions, String containerWidth, String containerHeight, ODTContext cfc) { + public ImageSettings(String xmlDirPath, String refFileName, String varWithOptions, String containerWidth, String containerHeight, File tmpDir, Queue assetFilesToInclude) { this.xmlDirPath = xmlDirPath; this.refFileName = refFileName; this.varOnly = varWithOptions; + this.assetFilesToInclude = assetFilesToInclude; Matcher alignMatcher = imageOptionsRegex.matcher(varWithOptions); if (alignMatcher.find()) { try { @@ -80,8 +82,8 @@ public ImageSettings(String xmlDirPath, String refFileName, String varWithOption //no need to throw it up as it is handled by readyToBeExecuted() } } - this.cfc = cfc; - this.dst = new File(cfc.template.tmpDir, ID()); + this.tmpDir = tmpDir; + this.dst = new File(tmpDir, ID()); } public String ID() { diff --git a/src/main/java/com/proxeus/document/odt/img/ImageVarProcessor.java b/src/main/java/com/proxeus/document/odt/img/ImageVarProcessor.java new file mode 100644 index 0000000..4241b7b --- /dev/null +++ b/src/main/java/com/proxeus/document/odt/img/ImageVarProcessor.java @@ -0,0 +1,60 @@ +package com.proxeus.document.odt.img; + +import com.proxeus.xml.processor.XMLEventProcessor; +import com.proxeus.xml.template.TemplateVarParser; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ImageVarProcessor implements XMLEventProcessor { + private final static String NAME_SPACE = "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"; + private final static Pattern imageOptionsRegex = Pattern.compile("(.*)\\[([^\\[\\]]*)\\]"); + + private TemplateVarParser varParser; + + public ImageVarProcessor(TemplateVarParser varParser) { + this.varParser = varParser; + } + + @Override + public void process(XMLEventReader reader, XMLEventWriter writer) throws XMLStreamException, IllegalStateException { + while (reader.hasNext()) { + XMLEvent e = reader.nextEvent(); + writer.add(e); + + if (!e.isStartElement()) { + continue; + } + + StartElement s = e.asStartElement(); + if (!s.getName().equals(new QName(NAME_SPACE, "frame"))) { + continue; + } + Attribute attribute = s.getAttributeByName(new QName(NAME_SPACE, "name")); + if (attribute == null) { + continue; + } + + String varWithOptions = attribute.getValue().trim(); + if (!(varWithOptions.startsWith("{{") && varWithOptions.endsWith("}}"))) { + //continue as there is no valid var expression and therefore nothing for us to do on this image tag + continue; + } + + Matcher alignMatcher = imageOptionsRegex.matcher(varWithOptions); + if (!alignMatcher.find()) { + continue; + } + varWithOptions = alignMatcher.group(1).trim(); + + varParser.parse(varWithOptions); + } + } +} diff --git a/src/main/java/com/proxeus/office/libre/LibreConfig.java b/src/main/java/com/proxeus/office/libre/LibreConfig.java index 8819887..6ded697 100644 --- a/src/main/java/com/proxeus/office/libre/LibreConfig.java +++ b/src/main/java/com/proxeus/office/libre/LibreConfig.java @@ -7,6 +7,7 @@ public class LibreConfig { /** * "/opt/libreoffice5.4/program" "C:/Program Files/LibreOffice 5/program" "/usr/lib/libreoffice/program" + * "/Applications/LibreOffice.app/Contents/MacOS/soffice" **/ public String librepath = "/usr/lib/libreoffice/program"; /** @@ -20,4 +21,4 @@ public class LibreConfig { /** highLoad defines the percentage of executables in use, when it is reached prepare new ones to be ready for high availability and fast response.**/ public int highLoad = 60; -} \ No newline at end of file +} diff --git a/src/main/java/com/proxeus/office/libre/LibreOfficeAssistant.java b/src/main/java/com/proxeus/office/libre/LibreOfficeAssistant.java index 397a329..fc55b1f 100644 --- a/src/main/java/com/proxeus/office/libre/LibreOfficeAssistant.java +++ b/src/main/java/com/proxeus/office/libre/LibreOfficeAssistant.java @@ -1,9 +1,11 @@ package com.proxeus.office.libre; +import com.proxeus.document.TemplateFormatter; import com.proxeus.error.UnavailableException; import com.proxeus.office.libre.exe.Extension; import com.proxeus.office.libre.exe.LibreOffice; import com.proxeus.office.libre.exe.LibreOfficePool; +import org.apache.log4j.Logger; import java.io.Closeable; import java.io.File; @@ -12,7 +14,9 @@ /** * LibreOfficeAssistant makes the communication between LibreOffice and the Document-Service easier and safely. */ -public class LibreOfficeAssistant implements Closeable { +public class LibreOfficeAssistant implements TemplateFormatter, Closeable { + private Logger log = Logger.getLogger(this.getClass()); + private LibreOfficePool libreOfficePool; public LibreOfficeAssistant(LibreConfig libreConfig) throws Exception { @@ -21,25 +25,12 @@ public LibreOfficeAssistant(LibreConfig libreConfig) throws Exception { } libreOfficePool = new LibreOfficePool(libreConfig); final Thread mainThread = Thread.currentThread(); - Runtime.getRuntime().addShutdownHook(new Thread() { - public void run() { - libreOfficePool.close(); - try{ - mainThread.join(); - }catch (Exception e){} - } - }); - } - - /** - * Convert src as the provided format at dst. - * @param src srouce file - * @param dst destination file - * @param format pdf, odt, docx or doc - * @return contentType - */ - public String Convert(File src, File dst, String format) throws Exception { - return Convert(src, dst, format, false); + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + libreOfficePool.close(); + try{ + mainThread.join(); + }catch (Exception e){} + })); } /** @@ -50,14 +41,27 @@ public String Convert(File src, File dst, String format) throws Exception { * @param newFontsInstalled signal new fonts are installed, to restart the executables so the font can be used * @return contentType */ + @Override public String Convert(File src, File dst, String format, boolean newFontsInstalled) throws Exception { + LibreOffice lo = null; + try{ + lo = libreOfficePool.take(newFontsInstalled); + }catch(Exception e){ + throw new UnavailableException("Please try again later.", e); + }finally { + libreOfficePool.release(); + } + + if (lo == null){ + throw new UnavailableException("Cannot initialize LibreOffice instance. Please try again later."); + } + int count = 0; do{ try{ - LibreOffice lo = libreOfficePool.take(newFontsInstalled); - newFontsInstalled = false; return lo.Convert(src, dst, format); }catch(ExceptionInInitializerError wiie){ + wiie.printStackTrace(); ++count; }catch(Exception e){ throw new UnavailableException("Please try again later.", e); @@ -65,7 +69,7 @@ public String Convert(File src, File dst, String format, boolean newFontsInstall libreOfficePool.release(); } }while(count < 10); - throw new UnavailableException("Please try again later."); + throw new UnavailableException("Cannot initialize LibreOffice instance. Please try again later."); } /** @@ -75,14 +79,12 @@ public String Convert(File src, File dst, String format, boolean newFontsInstall */ public Extension getExtension(String os){ try { - Extension ext = new Extension(); - ext.contentType = "application/octet-stream"; - ext.fileName = "ProxeusTemplateAssistance_" + os + ".oxt"; - InputStream fis = LibreOfficeAssistant.class.getResourceAsStream("/" + ext.fileName); + Extension ext = new Extension("ProxeusTemplateAssistance_" + os + ".oxt", "application/octet-stream"); + InputStream fis = LibreOfficeAssistant.class.getResourceAsStream("/" + ext.getFileName()); if (fis == null) { return null; } - ext.inputStream = fis; + ext.setInputStream(fis); return ext; } catch (Exception e) {} return null; diff --git a/src/main/java/com/proxeus/office/libre/conn/OOoServer.java b/src/main/java/com/proxeus/office/libre/conn/OOoServer.java index 4fbb02b..24eb7b6 100644 --- a/src/main/java/com/proxeus/office/libre/conn/OOoServer.java +++ b/src/main/java/com/proxeus/office/libre/conn/OOoServer.java @@ -2,15 +2,9 @@ import com.sun.star.comp.helper.BootstrapException; import com.sun.star.lib.util.NativeLibraryLoader; - import org.apache.commons.io.FileUtils; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintStream; +import java.io.*; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; diff --git a/src/main/java/com/proxeus/office/libre/exe/Extension.java b/src/main/java/com/proxeus/office/libre/exe/Extension.java index 760cab5..c1f1b2b 100644 --- a/src/main/java/com/proxeus/office/libre/exe/Extension.java +++ b/src/main/java/com/proxeus/office/libre/exe/Extension.java @@ -6,7 +6,36 @@ * A helper to return the LibreOffice extension from LibreOfficeAssistance. */ public class Extension { - public InputStream inputStream; - public String fileName; - public String contentType; + private InputStream inputStream; + private String fileName; + private String contentType; + + public Extension(String fileName, String contentType) { + this.fileName = fileName; + this.contentType = contentType; + } + + public InputStream getInputStream() { + return inputStream; + } + + public void setInputStream(InputStream inputStream) { + this.inputStream = inputStream; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getContentType() { + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } } diff --git a/src/main/java/com/proxeus/office/libre/exe/LibreOffice.java b/src/main/java/com/proxeus/office/libre/exe/LibreOffice.java index a4f1826..ea455c4 100644 --- a/src/main/java/com/proxeus/office/libre/exe/LibreOffice.java +++ b/src/main/java/com/proxeus/office/libre/exe/LibreOffice.java @@ -13,13 +13,7 @@ import com.sun.star.frame.XStorable; import com.sun.star.lang.DisposedException; import com.sun.star.lang.XComponent; -import com.sun.star.sheet.CellFlags; -import com.sun.star.sheet.XCalculatable; -import com.sun.star.sheet.XCellRangesQuery; -import com.sun.star.sheet.XSheetCellRanges; -import com.sun.star.sheet.XSpreadsheet; -import com.sun.star.sheet.XSpreadsheetDocument; -import com.sun.star.sheet.XSpreadsheets; +import com.sun.star.sheet.*; import com.sun.star.table.XCell; import com.sun.star.text.XDocumentIndex; import com.sun.star.text.XDocumentIndexesSupplier; @@ -30,12 +24,7 @@ import com.sun.star.util.XCloseable; import com.sun.star.util.XRefreshable; -import java.io.Closeable; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; +import java.io.*; import java.math.BigDecimal; import java.nio.file.Files; import java.nio.file.StandardCopyOption; @@ -66,7 +55,7 @@ public LibreOffice(String exeDir, boolean connect) throws java.lang.Exception { public String Convert(File src, File dst, String format) throws java.lang.Exception { LibreOfficeFormat lof = LibreOfficeFormat.get(format); exportDocument(src, dst, lof); - return lof.contentType; + return lof.getContentType(); } /** @@ -79,8 +68,7 @@ public boolean reconnect(long reconnectStamp) throws java.lang.Exception { if (con != null) { con.disconnect(); } - //BootstrapPipeConnector c = new BootstrapPipeConnector(exeDir); - //c.connect(); + BootstrapSocketConnector c = new BootstrapSocketConnector(exeDir); c.connect(); con = c; @@ -96,10 +84,8 @@ public boolean needToReconnect(long reconnectStamp) { private void exportDocument(File src, File dst, LibreOfficeFormat outputFormat) throws java.lang.Exception { try { - //InputStream input = new FileInputStream(src); - //OOInputStream ooInputStream = new OOInputStream(input); String sUrl = src.toURI().toString(); - XComponent oDocToStore = null; + XComponent oDocToStore; try { oDocToStore = con.getCompLoader().loadComponentFromURL(sUrl, "_blank", 0, createProps( p("Hidden", Boolean.TRUE), @@ -111,10 +97,10 @@ private void exportDocument(File src, File dst, LibreOfficeFormat outputFormat) )); if (oDocToStore == null) { lastReconnect = -1;//force reconnect - throw new ExceptionInInitializerError("Please try again later."); + throw new ExceptionInInitializerError("No doc to store. No Please try again later."); } } catch (NullPointerException eee) { - throw new ExceptionInInitializerError("Please try again later."); + throw new ExceptionInInitializerError("Internal error. Please try again later."); } try { @@ -152,7 +138,7 @@ private void exportDocument(File src, File dst, LibreOfficeFormat outputFormat) } xStorable.storeToURL(sUrl, createProps( p("Overwrite", Boolean.TRUE), - p("FilterName", outputFormat.filterName), + p("FilterName", outputFormat.getFilterName()), p("Hidden", Boolean.TRUE) //p("OutputStream", out) )); diff --git a/src/main/java/com/proxeus/office/libre/exe/LibreOfficeFormat.java b/src/main/java/com/proxeus/office/libre/exe/LibreOfficeFormat.java index 514d6bb..22caa20 100644 --- a/src/main/java/com/proxeus/office/libre/exe/LibreOfficeFormat.java +++ b/src/main/java/com/proxeus/office/libre/exe/LibreOfficeFormat.java @@ -10,9 +10,10 @@ public enum LibreOfficeFormat { MS_DOCX("MS Word 2007 XML", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "docx"), MS_DOC("MS Word 97", "application/msword", "doc"); - public final String filterName; - public final String contentType; - public final String ext; + private final String filterName; + private final String contentType; + private final String ext; + LibreOfficeFormat(String fn, String ct, String ext){ this.filterName = fn; this.contentType = ct; @@ -38,4 +39,16 @@ public static LibreOfficeFormat get(String format) throws Exception{ throw new Exception(format + " is not supported"); } } + + public String getFilterName() { + return filterName; + } + + public String getContentType() { + return contentType; + } + + public String getExt() { + return ext; + } } \ No newline at end of file diff --git a/src/main/java/com/proxeus/office/libre/exe/LibreOfficePool.java b/src/main/java/com/proxeus/office/libre/exe/LibreOfficePool.java index 5a5349e..b5f56f8 100644 --- a/src/main/java/com/proxeus/office/libre/exe/LibreOfficePool.java +++ b/src/main/java/com/proxeus/office/libre/exe/LibreOfficePool.java @@ -2,6 +2,7 @@ import com.proxeus.error.UnavailableException; import com.proxeus.office.libre.LibreConfig; +import org.apache.log4j.Logger; import java.lang.reflect.Field; import java.security.InvalidParameterException; @@ -31,6 +32,8 @@ * This class makes the horror more than just acceptable. */ public class LibreOfficePool { + private Logger log = Logger.getLogger(this.getClass()); + private LinkedBlockingDeque executables; private LinkedBlockingQueue toBeReleased; private LinkedBlockingQueue toReconnect; @@ -154,7 +157,7 @@ public void run() { } } } catch (Exception e) { - System.out.println("shutting down libre pool cleanup"); + log.info("shutting down libre pool cleanup"); } //shutdown @@ -273,7 +276,7 @@ public LibreOffice take(boolean reconnect) throws Exception { //looks like the service is under heavy load, lets throw and exceptions saying try again later //holding the request longer doesn't make sense as it takes more resources if (lo == null) { - throw new UnavailableException("Please try again later."); + throw new UnavailableException("All LibreOffice instances busy. Please try again later."); } } else { //try poll @@ -282,7 +285,7 @@ public LibreOffice take(boolean reconnect) throws Exception { offerNew(); lo = executables.poll(8, TimeUnit.SECONDS); if (lo == null) { - throw new UnavailableException("Please try again later."); + throw new UnavailableException("Cannot get LibreOffice instance. Please try again later."); } } } diff --git a/src/main/java/com/proxeus/office/microsoft/MicrosoftOfficeAssistant.java b/src/main/java/com/proxeus/office/microsoft/MicrosoftOfficeAssistant.java index 1c17fea..b90fa4e 100644 --- a/src/main/java/com/proxeus/office/microsoft/MicrosoftOfficeAssistant.java +++ b/src/main/java/com/proxeus/office/microsoft/MicrosoftOfficeAssistant.java @@ -1,10 +1,12 @@ package com.proxeus.office.microsoft; +import com.proxeus.error.NotImplementedException; + /** * Implement here the interaction between this service and Microsoft office. */ public class MicrosoftOfficeAssistant { - public MicrosoftOfficeAssistant(){ - //TODO impl if demanded + public MicrosoftOfficeAssistant() throws NotImplementedException { + throw new NotImplementedException("MicrosoftOfficeAssistant not implemented."); } } \ No newline at end of file diff --git a/src/main/java/com/proxeus/util/Image.java b/src/main/java/com/proxeus/util/Image.java index 040f71c..e21635e 100644 --- a/src/main/java/com/proxeus/util/Image.java +++ b/src/main/java/com/proxeus/util/Image.java @@ -1,10 +1,9 @@ package com.proxeus.util; +import javax.imageio.ImageIO; import java.io.File; import java.io.IOException; -import javax.imageio.ImageIO; - /** * Image helps us to create a container in which it places the actual image as configured with the parameters. * The container will be invisible as the output is always png. diff --git a/src/main/java/com/proxeus/util/zip/Zip.java b/src/main/java/com/proxeus/util/zip/Zip.java index ba96723..98c5b73 100644 --- a/src/main/java/com/proxeus/util/zip/Zip.java +++ b/src/main/java/com/proxeus/util/zip/Zip.java @@ -1,15 +1,10 @@ package com.proxeus.util.zip; import com.proxeus.SparkServer; - import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Files; @@ -26,7 +21,7 @@ import java.util.zip.ZipOutputStream; /** - * Zip extract and pack helper. + * Zip process and pack helper. */ public class Zip { public static void extract(InputStream zipStream, EntryFilter ef) throws Exception { @@ -106,7 +101,7 @@ public static File zipEntryToFile(ZipEntry zipEntry, InputStream inputStream, Fi if (zipEntry.isDirectory()) { if (!file.exists()) { if (!file.mkdirs()) { - throw new IOException("Could not extract asset(image?) from ZIP:" + file.getAbsolutePath()); + throw new IOException("Could not process asset(image?) from ZIP:" + file.getAbsolutePath()); } } } else { diff --git a/src/main/java/com/proxeus/xml/Code.java b/src/main/java/com/proxeus/xml/Code.java deleted file mode 100644 index 064d68f..0000000 --- a/src/main/java/com/proxeus/xml/Code.java +++ /dev/null @@ -1,400 +0,0 @@ -package com.proxeus.xml; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.regex.Pattern; - -/** - * Code is responsible for the correct relations and meaningful placement of code nodes. - */ -public class Code { - protected boolean isComment; - protected CodeType codeType; - protected List relations; - private boolean needsToMatchParentExactly = false; - - protected Code(CodeType codeType, Node...n) { - this.codeType = codeType; - relations = new ArrayList<>(n.length); - for(Node node : n){ - relations.add(node); - } - } - - /** - * Prepend code relation is needed for the main loop back. - * As we start with the end of a block. - * @param code related to the once we already have in relations - */ - protected void prepend(Node code){ - relations.add(0, code); - } - - /** - * Check whether we have the same parent on all codes. - * @return true if the parents are the same otherwise false - */ - protected boolean haveTheSameParent(){ - Node p = relations.get(0); - if(p == null){ - return false; - } - p = p.parent; - Node loopNode = null; - for (int i = 1; i < relations.size(); ++i) { - loopNode = relations.get(i); - if(loopNode == null || p != loopNode.parent){ - return false; - } - } - return true; - } - - /** - * Check wether it is a macro block like {% macro ...%} - */ - protected boolean isMacroBlock(){ - return codeType == CodeType.CodeBlock && relations.get(0).name().equals("macro"); - } - - /** - * To support simple macro usage by {{macros.function...}} - * and to recognize it via *macros.* so we can remove the empty wrappers safely on {{..}} too - * the removal is important to support inline paragraph templates - **/ - protected void doMacroImport(){ - if(relations.size()==2){ - Node endMacro = relations.get(1); - int indexOfEndMacro = endMacro.parent.children.indexOf(endMacro); - StringBuffer sb = new StringBuffer("{% import _self as macros %}"); - Node macroNode = new Node(new Tag(CodeType.CodeBlock, sb, 0, sb.length(), TagType.START_AND_END)); - endMacro.parent.children.add(indexOfEndMacro+1, macroNode); - } - } - - private final static Pattern macroAndBlockUsageRegex = Pattern.compile("\\{\\{\\s*(macros\\.\\w+|block\\s*\\().*"); - /** - * Check whether we should remove empty XML wrappers around this code. - * Usually on output code like {{ ... }}, we do not remove wrappers as it would lead to unexpected content behaviour. - * But on blocks like {% if .. %} or {# comment #} we can remove it as long as there is no content between the parent and this code. - * Whitespace count as no content. - */ - protected boolean shouldRemoveEmptyXMLWrappersAroundThisCode(){ - return codeType==CodeType.CodeBlock || (codeType == CodeType.Output && macroAndBlockUsageRegex.matcher(relations.get(0).start.toCharSequence()).matches()); - } - - protected Node findTheCommonParent() { - List relatedNodes = new ArrayList<>(relations.size()); - relatedNodes.addAll(relations); - needsToMatchParentExactly = true; - findNextCommonDepthLevel(relatedNodes); - return relatedNodes.get(0); - } - - /** - * Find the next common depth level to be able to move code suitable. - * @param config provides a code type specific setting. - * In case the depth level is not enough and the pieces are expected to be on the same parent. - * @return depth level - */ - protected int findNextCommonDepthLevel(Config config) { - //create a new list so we can modify the entries if necessary to find the common parent - List relatedNodes = new ArrayList<>(relations.size()); - relatedNodes.addAll(relations); - needsToMatchParentExactly = config.NeedsToMatchParentExactly(this); - return findNextCommonDepthLevel(relatedNodes); - } - - protected int findNextCommonDepthLevel(List relatedNodes){ - //calculate depth - int i = 0; - int c = relatedNodes.size(); - Node p = null; - int min = Integer.MAX_VALUE; - int max = -1; - - int[] depths = new int[c]; - for (; i < c; ++i) { - p = relatedNodes.get(i); - //not handling the last lvl before root - //but so far it is anyway not needed - if (p.parent != null) { - if (max < p.getDepth(true)) { - max = p.depth; - } - if (min > p.depth) { - min = p.depth; - } - depths[i] = p.depth; - p = p.parent; - relatedNodes.set(i, p); - } - } - - if(min == max && matchesParentOrTheSameType(relatedNodes)){ - /** - * If parent matches correctly. - * - * -------------------OR------------------------ - * - * If parent is just of the same type and on the same depth level. - * - * It is still cutting but not across, it will lead to a valid structure. - * - * Example: - * before if >>>|{if false} after if - * before else..{else}|<< - * - * Outcome: - * before if >>>||<< - */ - return -1; - } - - /** - * give it a try with the current min depth and keep trying until 0 - * if the common depth didn't provide the same parent type - */ - for(;min>0;--min){ - //use the closest depth to find the common parent or the parent with the same depth level and type - for (i = 0; i < relatedNodes.size(); ++i) { - if (min < depths[i]) { - int diff = depths[i] - min; - p = relatedNodes.get(i); - for (int d = 0; d < diff; ++d) { - if (p.parent != null) { - p = p.parent; - --depths[i]; - if(min>depths[i]){ - min = depths[i]; - } - } - } - relatedNodes.set(i, p); - } - } - - if(sameDepths(depths) && matchesParentOrTheSameType(relatedNodes)){ - return depths[0]; - } - } - return -1; - } - - /** - * @param depths check whether the sequence contains the exact same value on all the entries - * @return true if all values are the same else false - */ - private boolean sameDepths(int[] depths) { - int firstDepth = depths[0]; - for(int i = 1; i < depths.length; ++i){ - if(firstDepth!=depths[i]){ - return false; - } - } - return true; - } - - /** - * Checks if this code needs to match parent exactly otherwise of the same parent type. - * @param relatedNodes containing the parents - * @return true if all the parents in the list are the exact same or of the same type - */ - private boolean matchesParentOrTheSameType(List relatedNodes) { - if(needsToMatchParentExactly){ - return matchesParentOnAll(relatedNodes); - } - return sameParentTypeOnAll(relatedNodes); - } - - /** - * The parent is exactly the same. - */ - private boolean matchesParentOnAll(List relatedNodes) { - Node p = relatedNodes.get(0); - for (int i = 1; i < relatedNodes.size(); ++i) { - if (relatedNodes.get(i) != p) { - return false; - } - } - return true; - } - - /** - * The parent could be the exact same or just of the same type. - * Same type means it all have the same tag name. - */ - private boolean sameParentTypeOnAll(List relatedNodes) { - Node p = relatedNodes.get(0); - for (int i = 1; i < relatedNodes.size(); ++i) { - if (!relatedNodes.get(i).name().equals(p.name())) { - return false; - } - } - return true; - } - - /** - * Are there any children? - * @return true if there are otherwise false - */ - protected boolean hasChilds() { - for(Node n : relations){ - if(n.hasChildren()){ - return true; - } - } - return false; - } - - /** - * Try to find the best suited tags for this code to wrap. - * @param xmlTagNames the configured and best suited tags - * @param maxRange when to give up for end and start code - */ - protected void tryToWrapXMLTag(Set xmlTagNames, int maxRange) { - //The one with the shortest distance will be chosen in case there are many. - Measurement[] ms = new Measurement[]{new Measurement(), new Measurement(), new Measurement()}; - ms[0].measureDistanceOutsideUp(relations.get(0), xmlTagNames, maxRange); - ms[1].measureDistanceOutsideDown(relations.get(0), xmlTagNames, maxRange); - ms[2].measureDistanceInsideDown(relations.get(0), xmlTagNames, maxRange); - Arrays.sort(ms, new Comparator() { - public int compare(Measurement left, Measurement right) { - if(left.isXMLThatNeedsToBeWrapped && (left.distance xmlTagName = new HashSet<>(1); - xmlTagName.add(m.node.name()); - Measurement endCodeMeasurement = new Measurement(); - if(depthOfXMLToBeWrapped < depthOfEndCode){ - endCodeMeasurement.measureDistanceOutsideDown(endCode, xmlTagName, maxRange); - }else{ - endCodeMeasurement.measureDistanceInsideUp(endCode, xmlTagName, maxRange); - } - if(endCodeMeasurement.isXMLThatNeedsToBeWrapped){ - if(m.node == endCodeMeasurement.node || depthOfXMLToBeWrapped == endCodeMeasurement.node.getDepth(true)){ - //wrap start code - startCode.wrapAround(m.node); - //wrap end code - endCode.wrapAround(endCodeMeasurement.node); - return true; - } - } - return false; - } - - /** - * Retrieve the first node. - */ - protected Node firstNode(){ - return relations.get(0); - } - - /** - * Retrieve the first node. - */ - protected Node lastNode(){ - return relations.get(relations.size()-1); - } - - /** - * As code will be written as document content, it gets messed up. - * This method is the initial method that ensures it gets moved to the next suitable and meaningful place. - */ - protected void moveToCommonParent(Config config) { - moveOutsideToParent(findNextCommonDepthLevel(config)); - } - - /** - * With the common depth level and the related code nodes we can no start to try our way to place them meaningful. - * @param commonDepth of all the nodes in relations - */ - protected void moveOutsideToParent(int commonDepth) { - if (commonDepth<=-1) { - return; - } - for(Node n : relations){ - if (n.depth > commonDepth) { - n.moveOutsideToParent(commonDepth); - } - } - } - - public String toString() { - StringBuilder sb = new StringBuilder(); - toString(sb); - return sb.toString(); - } - - /** - * Assuming all code relations have the same parent otherwise it leads to unexpected behaviours. - */ - public void toString(StringBuilder sb) { - Node lastRelatedNode = null; - for(Node codeNode : relations){ - if(lastRelatedNode!=null){ - if(lastRelatedNode.parent!= null){ - int indexOfMe = lastRelatedNode.parent.children.indexOf(lastRelatedNode); - Element sibling = null; - for(int i = indexOfMe+1; i < lastRelatedNode.parent.children.size(); ++i){ - sibling = lastRelatedNode.parent.children.get(i); - if(sibling == codeNode){ - break; - } - sibling.toString(sb); - } - } - } - codeNode.toString(sb); - lastRelatedNode = codeNode; - } - } -} diff --git a/src/main/java/com/proxeus/xml/CodeType.java b/src/main/java/com/proxeus/xml/CodeType.java deleted file mode 100644 index 179f7f0..0000000 --- a/src/main/java/com/proxeus/xml/CodeType.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.proxeus.xml; - -public enum CodeType { - NoCode, - //{% ... %} - CodeBlock, - //{{ ... }} - Output, - //{# ... #} - Comment; - - public boolean isCode(){ - return this != NoCode; - } - public boolean isNoCode(){ - return this == NoCode; - } -} \ No newline at end of file diff --git a/src/main/java/com/proxeus/xml/Compiled.java b/src/main/java/com/proxeus/xml/Compiled.java deleted file mode 100644 index fe0dc46..0000000 --- a/src/main/java/com/proxeus/xml/Compiled.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.proxeus.xml; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; - - -/** - * Compiled helps to compile and replace an actual element in the XML structure to prevent from compiling the entire thing. - * For example: - * - * - * ... - * - * - * ... - * ... - * - * - * - * ... - * <---- this is the only root node that needs to be complied - * {%if%}.. - * - * - * - * ... - * - * - * - * - * By just taking instead of the entire thing to be compiled, we increase performance a lot. - * - * After replacing the un-compiled element with this one, the toOutputStream method or any other output method can be used as usual. - */ -public class Compiled extends Element{ - private ByteArrayOutputStream outputStream; - - public Compiled(){ - outputStream = new ByteArrayOutputStream(); - } - - public void toOutputStream(OutputStream os, Charset charset) throws IOException { - outputStream.writeTo(os); - } - - public String toString() { - StringBuilder sb = new StringBuilder(); - toString(sb); - return sb.toString(); - } - - public InputStream toInputStream(Charset charset){ - return new ByteArrayInputStream(outputStream.toByteArray()); - } - - public void toString(StringBuilder sb) { - //charset missing here just taking UTF-8 as default as I assume this would be called only for debugging purposes - sb.append(new String(outputStream.toByteArray(), StandardCharsets.UTF_8)); - } - - public OutputStream getOutputStream(){ - return outputStream; - } -} \ No newline at end of file diff --git a/src/main/java/com/proxeus/xml/Config.java b/src/main/java/com/proxeus/xml/Config.java index b362674..eb94e1d 100644 --- a/src/main/java/com/proxeus/xml/Config.java +++ b/src/main/java/com/proxeus/xml/Config.java @@ -6,7 +6,7 @@ import java.util.Set; /** - * Config for XmlTemplateHandler + * Config for TemplateHandler */ public class Config { @@ -52,9 +52,6 @@ public void AddCodeThatNeedsToMatchParentExactly(String...n){ MatchParentExactlyCodes.add(codeName); } } - public boolean NeedsToMatchParentExactly(Code code){ - return code.codeType==CodeType.CodeBlock && MatchParentExactlyCodes.contains(code.relations.get(0).name()); - } //false means tags are not going to be fixed with an end or start tag close to the wrong tag public boolean Fix_XMLTags; diff --git a/src/main/java/com/proxeus/xml/Element.java b/src/main/java/com/proxeus/xml/Element.java deleted file mode 100644 index 89c9fc1..0000000 --- a/src/main/java/com/proxeus/xml/Element.java +++ /dev/null @@ -1,421 +0,0 @@ -package com.proxeus.xml; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.regex.Pattern; - -/** - * Element is the base class of Node and it represents either XML, code or text. - */ -public class Element { - public List children; - public ElementType type; - public Tag start; - public Tag end; - public Node parent; - public int depth; - - public Element() {} - - // this constructor is only used for text - public Element(Tag start){ - this.start = start; - type = ElementType.TEXT; - } - - /** - * Create an end tag out of the start tag. - */ - public void createEndTag() { - setEnd(start.createEndTag()); - } - - /** - * Create a start tag out of the end tag. - */ - public void createStartTag() { - setStart(end.createStartTag()); - } - - /** - * Remove this element only and move the children to the parent at the same position. - */ - public void removeThisElementButKeepTheChildren(){ - if(hasChildren()){ - int indexOfMe = parent.children.indexOf(this); - parent.addChildsAfter(indexOfMe, children); - } - remove(); - } - - /** - * Replace this with newNode. - * If parent is null, it will do nothing. - * Which means replacing the root node is not supported. - */ - public void replaceWith(Element newElement){ - if(parent != null){ - int indexOfMe = parent.children.indexOf(this); - parent.children.set(indexOfMe, newElement); - newElement.parent = parent; - } - } - - /** - * Just remove this element. - */ - public void remove(){ - parent.children.remove(this); - } - - /** - * Set the start tag of this element. - * @param s the start tag - */ - public void setStart(Tag s) { - start = s; - if (type == null && start != null) { - if (start.isCode()) { - type = ElementType.CODE; - } else { - type = ElementType.XML; - } - } - } - - /** - * Set the end tag of this element. - * @param e the end tag - */ - public void setEnd(Tag e) { - end = e; - if (type == null && end != null) { - if (end.isCode()) { - type = ElementType.CODE; - } else { - type = ElementType.XML; - } - } - } - - /** - * Check whether this element has an end tag. - * @return false it has an end tag otherwise true - */ - public boolean hasNoEndTag() { - if (start != null && start.type == TagType.START_AND_END) { - return false; - } - return end == null; - } - - /** - * Check whether this element a start and end tag. - * @return true if it has otherwise false - */ - public boolean hasStartAndEndTag() { - return start != null && end != null; - } - - /** - * Check whether this element has no start tag. - * @return true if it doesn't otherwise false - */ - public boolean hasNoStartTag() { - return start == null; - } - - /** - * Check whether it has only an end tag. - * @return true if it has otherwise false - */ - public boolean isEndTagOnly(){ - return start == null; - } - - /** - * Get the previous sibling of this element but skip whitespace elements. - * @return the previous element or @null if there was only whitespaces or no siblings - */ - public Element prevSibling() { - if(parent==null){ - return null; - } - int indexOfMe = parent.children.indexOf(this); - Element e; - do { - --indexOfMe; - if (indexOfMe < 0) { - return null; - } - e = parent.children.get(indexOfMe); - } while (e.isWhiteSpaceOnlyElement()); - return e; - } - - /** - * Next sibling without whitespace elements. - * @return next sibling element - */ - public Element nextSibling() { - if(parent==null){ - return null; - } - int indexOfMe = parent.children.indexOf(this); - return nextSiblingOfIndex(indexOfMe); - } - - /** - * Next sibling by the provided index. - * @return the next element or null - */ - public Element nextSiblingOfIndex(int indexOfMe) { - if(parent==null){ - return null; - } - int s = parent.children.size(); - Element e; - do { - ++indexOfMe; - if (indexOfMe == s) { - return null; - } - e = parent.children.get(indexOfMe); - } while (e.isWhiteSpaceOnlyElement()); - return e; - } - - /** - * Get the first child of this element but skip whitespace elements. - * @return first child element or @null if there was only whitespaces or no children - */ - public Element firstChild(){ - if(hasChildren()){ - Element e; - for(int i = 0; i < children.size(); ++i){ - e = children.get(i); - if(e.isWhiteSpaceOnlyElement()){ - continue; - } - return e; - } - } - return null; - } - - /** - * Get the last child of this element but skip whitespace elements. - * @return last child element or @null if there was only whitespaces or no children - */ - public Element lastChild(){ - if(hasChildren()){ - Element e; - for(int i = children.size()-1; i > -1; --i){ - e = children.get(i); - if(e.isWhiteSpaceOnlyElement()){ - continue; - } - return e; - } - } - return null; - } - - /** - * Check whether #onlyChild is the only child of this element but do not count whitespace elements in. - * @param onlyChild the element that needs to be checked - * @return true if it is the only child with or without whitespace elements - */ - public boolean withoutWhitespacesTheOnlyChildIs(Node onlyChild) { - if (hasChildren()) { - int index = children.indexOf(onlyChild); - if(index > -1){ - //onlyChild is really a child of this parent - int count = 0; - Iterator elementIterator = children.iterator(); - while (count < 2 && elementIterator.hasNext()) { - Element e = elementIterator.next(); - if (e.isWhiteSpaceOnlyElement()) { - continue; - } - ++count; - } - if(count == 1){ - //onlyChild is indeed the only child of this parent - return true; - } - } - } - return false; - } - - /** - * The depth level in the XML structure counting from root to the position of this element. - * @param calculate true if it should be recalculated - * @return depth level - */ - public int getDepth(boolean calculate) { - if(calculate){ - depth = -1; - } - return getDepth(); - } - - /** - * The depth level in the XML structure counting from root to the position of this element. - * @return depth level - */ - public int getDepth() { - if (depth <= -1) { - depth = 1; - if (parent != null) { - for (Node p = parent; p != null; p = p.parent) { - ++depth; - } - } - } - return depth; - } - - /** - * The public method for finding elements recursively by name. - * @param name of the element you are looking for - * @return list of elements - */ - public List findElementByName(String name) { - ArrayList elements = new ArrayList<>(4); - innerFindElementByName(elements, name); - return elements; - } - - /** - * Find elements recursively by name. - * @param list to be filled with elements that matches the name - * @param name of the element you are looking for - */ - private void findElementByName(List list, String name){ - if (start != null && name.equals(start.name)) { - list.add(this); - } - innerFindElementByName(list, name); - } - - /** - * Helper method for findElementByName. - */ - private void innerFindElementByName(List list, String name){ - if (hasChildren()) { - Iterator elementIterator = children.iterator(); - while (elementIterator.hasNext()) { - Element e = elementIterator.next(); - e.findElementByName(list, name); - } - } - } - - /** - * write attr value - */ - public void attr(String attrName, String value) { - if(start == null){ - return; - } - start.attr(attrName, value); - } - - /** - * read attr value - */ - public String attr(String name){ - if(start == null){ - return null; - } - return start.attr(name); - } - - /** - * Does this element have children? - * @return true if it does - */ - public boolean hasChildren() { - return children != null && children.size() > 0; - } - - private final static Pattern whiteSpaceOnlyRegex = Pattern.compile("^\\s*$"); - /** - * Is this element a whitespace only element? - * @return true if it is - */ - public boolean isWhiteSpaceOnlyElement() { - return type == ElementType.TEXT && (start!=null && start.whiteSpacesOnly()); - } - - public String toString() { - StringBuilder sb = new StringBuilder(length()); - toString(sb); - return sb.toString(); - } - - public InputStream toInputStream(Charset charset){ - StringBuilder sb = new StringBuilder(length()); - toString(sb); - return new ByteArrayInputStream(sb.toString().getBytes(charset)); - } - - public void toString(StringBuilder sb) { - if (start != null) { - start.toString(sb); - } - - if (children != null && children.size() > 0) { - Iterator elementIterator = children.iterator(); - while (elementIterator.hasNext()) { - elementIterator.next().toString(sb); - } - } - - if (end != null) { - end.toString(sb); - } - } - - public void toOutputStream(OutputStream os, Charset charset) throws IOException { - if (start != null) { - start.toStream(os, charset); - } - - if (children != null && children.size() > 0) { - Iterator elementIterator = children.iterator(); - while (elementIterator.hasNext()) { - elementIterator.next().toOutputStream(os, charset); - } - } - - if (end != null) { - end.toStream(os, charset); - } - } - - public int length(){ - int len = 0; - if (start != null) { - len += start.length(); - } - if (children != null && children.size() > 0) { - Iterator elementIterator = children.iterator(); - while (elementIterator.hasNext()) { - len += elementIterator.next().length(); - } - } - if (end != null) { - len += end.length(); - } - return len; - } -} diff --git a/src/main/java/com/proxeus/xml/ElementType.java b/src/main/java/com/proxeus/xml/ElementType.java deleted file mode 100644 index db6f11f..0000000 --- a/src/main/java/com/proxeus/xml/ElementType.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.proxeus.xml; - -/** - * We differentiate only between XML, CODE or TEXT - * XML is everything that starts with < and ends with > like - * CODE is {% .. %}, {{ .. }} or {# .. #} - * TEXT is everything else - */ -public enum ElementType {XML, CODE, TEXT} \ No newline at end of file diff --git a/src/main/java/com/proxeus/xml/Measurement.java b/src/main/java/com/proxeus/xml/Measurement.java deleted file mode 100644 index b408a51..0000000 --- a/src/main/java/com/proxeus/xml/Measurement.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.proxeus.xml; - -import java.util.Set; - -/** - * Measurement helps to find the best way to the best suited nodes. - */ -public class Measurement { - int distance = 0; - Node node; - boolean isXMLThatNeedsToBeWrapped; - - protected Measurement() { - } - - protected void measureDistanceOutsideDown(Node target, Set xmlTagNames, int maxRange) { - node = target; - while (maxRange > 0 && !isXMLThatNeedsToBeWrapped && node.parent != null && node.nextSibling() == null) { - --maxRange; - nextStep(node.parent, xmlTagNames.contains(node.name())); - } - if (target.start != null) { - //try to move to the next sibling as it is a start tag - Element element = node.nextSibling(); - if (maxRange > 0 && element != null && element instanceof Node && xmlTagNames.contains(((Node) element).name())) { - nextStep((Node) element, true); - } - } - } - - protected void measureDistanceOutsideUp(Node target, Set xmlTagNames, int maxRange) { - node = target; - while (maxRange > 0 && !isXMLThatNeedsToBeWrapped && node.prevSibling() == null) { - if (node.parent != null) { - --maxRange; - nextStep(node.parent, xmlTagNames.contains(node.name())); - } - } - } - - protected void measureDistanceInsideDown(Node target, Set xmlTagNames, int maxRange) { - node = target; - Element element; - while (maxRange > 0 && - !isXMLThatNeedsToBeWrapped && - ((element = node.firstChild()) != null || (element = node.nextSibling()) != null) && - element.type == ElementType.XML) { - --maxRange; - nextStep((Node) element, xmlTagNames.contains(node.name())); - } - } - - protected void measureDistanceInsideUp(Node target, Set xmlTagNames, int maxRange) { - node = target; - Element element; - if (maxRange > 0 && - !isXMLThatNeedsToBeWrapped && - (element = node.prevSibling()) != null && - element.type == ElementType.XML) { - --maxRange; - nextStep((Node) element, xmlTagNames.contains(node.name())); - while (maxRange > 0 && - !isXMLThatNeedsToBeWrapped && - node.hasStartAndEndTag() && - (element = node.lastChild()) != null && - element.type == ElementType.XML) { - --maxRange; - nextStep((Node) element, xmlTagNames.contains(node.name())); - } - } - } - - private void nextStep(Node n, boolean isOneOfOurTargets) { - ++distance; - node = n; - isXMLThatNeedsToBeWrapped = isOneOfOurTargets; - } - - /** - * help gc - */ - protected void free() { - node = null; - } -} \ No newline at end of file diff --git a/src/main/java/com/proxeus/xml/NoCopyCharSequence.java b/src/main/java/com/proxeus/xml/NoCopyCharSequence.java deleted file mode 100644 index 7e2b446..0000000 --- a/src/main/java/com/proxeus/xml/NoCopyCharSequence.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.proxeus.xml; - -public class NoCopyCharSequence implements CharSequence { - public StringBuffer buffer; - public int start; - public int end; - protected NoCopyCharSequence(StringBuffer b, int start, int end){ - this.buffer = b; - this.start = start; - this.end = end; - } - public int length() { - return end - start; - } - - public char charAt(int index) { - return this.buffer.charAt(start+index); - } - - public CharSequence subSequence(int start, int end) { - return this.buffer.subSequence(this.start+start, this.start+end); - } - - public String toString(){ - return this.buffer.substring(start, end); - } -} \ No newline at end of file diff --git a/src/main/java/com/proxeus/xml/Node.java b/src/main/java/com/proxeus/xml/Node.java deleted file mode 100644 index 2980f9f..0000000 --- a/src/main/java/com/proxeus/xml/Node.java +++ /dev/null @@ -1,285 +0,0 @@ -package com.proxeus.xml; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.Set; - -/** - * A Node in a well formed XML contains the following: - * //start tag - * a //children - * b //children - * //end tag - * or - * //start tag with type START_AND_END, end and childs are null - * - * A Node contains code elements too, but does not keep track of start or end nor children entirely. - * Each code element is kept in separated node. The children that are supposed to be the children of the code are the children of the code parent. - * This way we gain performance when we structure the code well in the XML structure instead of dragging children along. - * - * {%if%} //#NodeIf start - * //#NodeBody children - * {%endif%} //#NodeEndIf end - * - */ -public class Node extends Element { - public boolean interestingForLoopBack = true; - - public Node(Tag s) { - start = s; - if (start != null) { - if (start.codeType.isCode()) { - type = ElementType.CODE; - } else { - type = ElementType.XML; - } - } - } - - /** - * Before this method can be called, cautious analysis must be made to ensure - * the way is free without breaking the content - */ - protected void wrapAround(Node toBeWrapped){ - if(toBeWrapped==null || (start!=null && end!=null)){ - //don't do anything if this node is not missing either start or end tag - //as wrapping is only used for code - return; - } - int newIndex = toBeWrapped.parent.children.indexOf(toBeWrapped); - this.parent.children.remove(this); - this.parent = toBeWrapped.parent; - if(start != null && end == null){ - //wrap as start tag before the target - toBeWrapped.parent.children.add(newIndex, this); - }else if(start == null && end != null){ - //wrap as end tag after the target - toBeWrapped.parent.children.add(newIndex+1, this); - } - } - - /** - * @return the name of the XML tag or code. - * - * Example with XML tag name = "body" - * Example with code {% if %} name = "if" - * Example with different code {{input.date}} name = "" - */ - public String name() { - return start != null ? start.name : (end != null ? end.name : null); - } - - /** - * Add one child to the bottom of this node. - */ - public void addChild(Element e) { - if (children == null) { - children = new ArrayList<>(1); - } - e.parent = this; - children.add(e); - } - - /** - * Add children to the bottom of this node. - */ - public void addChilds(List children) { - if (children != null && children.size() > 0) { - if (this.children == null) { - this.children = new ArrayList<>(1); - } - Iterator elementIterator = children.iterator(); - while (elementIterator.hasNext()) { - Element e = elementIterator.next(); - e.parent = this; - this.children.add(e); - } - children.clear(); - } - } - - /** - * Add children after @param n. @param n must be a child of this very node already. - * If it is not a child of this node, nothing will happen. - * If it is a child of this node, the children will be appended after @param n and the children list will be cleared. - * @param n append after this child node - * @param children to be appended - */ - public void addChildsAfter(Node n, List children) { - int eleSize; - if (children != null && (eleSize = children.size()) > 0) { - if (this.children == null) { - this.children = new ArrayList<>(eleSize); - return; - } - addChildsAfter(this.children.indexOf(n), children); - } - } - - /** - * Add children after the provided index. - * If index is in range, the children will be appended at this index and the children list will be cleared. - * If index is -1 nothing will happen. If index is not childs.size() or smaller therefore not in range an exception will be thrown. - * @param i append at this index - * @param children to be appended - */ - public void addChildsAfter(int i, List children) { - if (children != null) { - if (this.children == null) { - this.children = new ArrayList<>(children.size()); - } - if (i > -1) { - ++i; - Element e = null; - for (int c = 0; c < children.size(); ++c) { - e = children.get(c); - e.parent = this; - this.children.add(i, e); - ++i; - } - children.clear(); - } - } - } - - /** - * Removes empty XML wrappers like: - * - *

//will be removed as white spaces are ignored - * //will be removed as white spaces are ignored - * {%if%} - * - *

- * - * If p and span are whitelisted to be removed in the config. - * Outcome: - * - * {%if%} - * - * If whitelistedTags is empty, nothing will happen. - * @param whitelistedTags - */ - public void removeEmptyXMLWrappers(Set whitelistedTags) { - while (parent != null && parent.parent != null && whitelistedTags.contains(parent.name()) && parent.withoutWhitespacesTheOnlyChildIs(this)) { - --depth; - int myNewIndex = parent.parent.children.indexOf(parent); - parent.parent.children.set(myNewIndex, this); - parent = parent.parent; - } - } - - /** - * This method tries to move the target outside the parent without moving the any text elements. - * By checking the previous siblings and next siblings. - * If there is no way out, the XML patterns are reconstructed to free the way for the target. - * @param commonDepth the depth level this method has to reach - */ - public void moveOutsideToParent(int commonDepth) { - while (depth > commonDepth) { - if (parent != null && parent.parent != null) { - //try to move outside down if it is end code - if(type == ElementType.CODE && start == null && nextSibling() == null){ - moveOutsideDown(); - continue; - } - if (prevSibling() == null) { - moveOutsideUp(); - } else { - moveOutsideDown(); - } - } - } - } - - /** - * This method should be called only if there are no previous siblings - * and the parent of the current parent is not null/root. - * - * 1. add children to the parent after the target if there are any - * 2. replace target with the parents position - * 3. get all the children from that position - */ - public void moveOutsideUp() { - int indexOfMe = parent.children.indexOf(this); - if(hasChildren()) { - parent.addChildsAfter(indexOfMe, children); - } - parent.children.remove(this); - Node oldPp = parent.parent; - int indexOfParent = oldPp.children.indexOf(parent); - oldPp.children.add(indexOfParent, this); - parent = oldPp; - --depth; - int si = oldPp.children.size(); - if(start != null && start.isNoCode() && start.type == TagType.START && si-1 > indexOfParent){ - children = new ArrayList<>(Math.max(si, indexOfParent) - Math.min(si, indexOfParent)); - ListIterator li = oldPp.children.listIterator(indexOfParent); - Element e = null; - while (li.hasNext()) { - e = li.next(); - e.parent = this; - --e.depth; - children.add(e); - li.remove(); - } - } - } - - /** - * 1. if has children or siblings -> new Node with a copy of the parent containing all children or siblings of the target - * 2. if it has children or siblings -> move target down and set the new Node as the child of the target or child of the targets parent, otherwise just move outside down - */ - public void moveOutsideDown() { - int i = parent.children.indexOf(this); - if (i > -1) { - if (hasChildren()) { - parent.children.remove(i); - Tag newStartTag = parent.start.copy(); - Node n = new Node(newStartTag); - n.setEnd(newStartTag.createEndTag()); - n.addChilds(children); - addChild(n); - i = parent.parent.children.indexOf(parent) + 1; - } else if (nextSiblingOfIndex(i) != null) { - parent.children.remove(i); - int si = parent.children.size(); - ArrayList nextSiblings = new ArrayList<>(Math.max(si, i) - Math.min(si, i)); - ListIterator li = parent.children.listIterator(i); - Tag newStartTag = parent.start.copy(); - Node n = new Node(newStartTag); - n.setEnd(newStartTag.createEndTag()); - Element e = null; - while (li.hasNext()) { - e = li.next(); - e.parent = n; - nextSiblings.add(e); - li.remove(); - } - n.children = nextSiblings; - i = parent.parent.children.indexOf(parent) + 1; - parent.parent.children.add(i, n); - n.parent = parent.parent; - } else { - parent.children.remove(i); - i = parent.parent.children.indexOf(parent) + 1; - } - parent.parent.children.add(i, this); - parent = parent.parent; - --depth; - } - } - - /** - * move children to the parent at the same position if there are any children - */ - public void moveChildsToParentAtTheSamePosition(){ - if (hasChildren()) { - //move the children to the parent and clear the childs list of this node - parent.addChildsAfter(this, children); - //set it to failed as we are not going to lookup for an end tag for this node anymore - interestingForLoopBack = false; - } - } -} diff --git a/src/main/java/com/proxeus/xml/Tag.java b/src/main/java/com/proxeus/xml/Tag.java deleted file mode 100644 index 7a3d7a4..0000000 --- a/src/main/java/com/proxeus/xml/Tag.java +++ /dev/null @@ -1,312 +0,0 @@ -package com.proxeus.xml; - -import org.apache.commons.text.StringEscapeUtils; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.charset.Charset; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * A Tag object keeps code, XML or text content. - * The StringBuffer is usually the main reference for XML or for text content. - * For code it is always a new buffer containing the cleaned code. - */ -public class Tag { - protected TagType type; - protected int startIndex; - protected int endIndex; - protected CodeType codeType = CodeType.NoCode; - protected String name; - /** - * To not copy unneccessary string we keep the buffer here. - * But we copy a string buffer for code though as it has to be cleaned. - */ - protected StringBuffer content; - private static final Pattern nameCodeReg = Pattern.compile("\\{%\\s*([^\\s\\/]+).*%\\}"); - private static final Pattern nameXmlReg = Pattern.compile("\\<\\/?([^\\s\\/]+).*\\/?\\>"); - private static final Pattern doubleQuotesEncodedRegex = Pattern.compile("("|“|”|„)"); - private static final Pattern singleQuotesEncodedRegex = Pattern.compile("('|’|‘|‚)"); - - public Tag() { - } - public Tag(String contnt, TagType type) { - this.codeType = CodeType.NoCode; - this.content = new StringBuffer(contnt); - this.startIndex = 0; - this.endIndex = contnt.length(); - this.type = type; - init(); - } - public Tag(StringBuffer sb, int startIndex, int endIndex, TagType type) { - this(CodeType.NoCode, sb, startIndex, endIndex, type); - } - - public Tag(CodeType codeType, StringBuffer sb, int startIndex, int endIndex, TagType type) { - this.codeType = codeType; - this.startIndex = startIndex; - this.endIndex = endIndex; - this.content = sb;//sb.substring(startIndex, endIndex); - this.type = type; - init(); - } - - public Tag(CodeType codeType, List styleTagsInsideCode, StringBuffer sb, int startIndex, int endIndex, TagType type) { - this.codeType = codeType; - this.startIndex = startIndex; - this.endIndex = endIndex; - this.type = type; - cleanCode(sb, styleTagsInsideCode); - init(); - } - - private void init(){ - if (codeType.isCode()) { - if(codeType ==CodeType.CodeBlock){ - Matcher m = nameCodeReg.matcher(toCharSequence()); - if (m.find()) { - this.name = m.group(1).toLowerCase(); - if (this.name.startsWith("end")) { - this.name = this.name.substring(3); - type = TagType.END; - } - } else { - this.name = ""; - } - }else{ - this.name = ""; - } - } else { - Matcher m = nameXmlReg.matcher(toCharSequence()); - this.name = m.find() ? m.group(1) : ""; - } - } - - public String toString() { - return this.content.substring(startIndex, endIndex); - } - - public CharSequence toCharSequence(){ - return new NoCopyCharSequence(content, startIndex, endIndex); - } - - public void toString(StringBuilder sb) { - sb.append(this.content.substring(startIndex, endIndex)); - } - - public void toStream(OutputStream sb, Charset charset) throws IOException { - sb.write(this.content.substring(startIndex, endIndex).getBytes(charset)); - } - - protected Tag copy() { - Tag t = new Tag(); - t.type = this.type; - t.codeType = this.codeType; - t.name = this.name; - t.content = this.content; - t.startIndex = this.startIndex; - t.endIndex = this.endIndex; - return t; - } - - protected Tag createEndTag() { - Tag t = new Tag(); - t.type = this.type; - t.codeType = this.codeType; - t.name = this.name; - String cont = ""; - t.content = new StringBuffer(cont); - t.startIndex= 0; - t.endIndex = cont.length(); - return t; - } - - protected Tag createStartTag() { - Tag t = new Tag(); - t.type = this.type; - t.codeType = this.codeType; - t.name = this.name; - String cont = "<" + this.name + ">"; - t.content = new StringBuffer(cont); - t.startIndex= 0; - t.endIndex = cont.length(); - return t; - } - - protected boolean isCode(){ - return codeType.isCode(); - } - - protected boolean isNoCode(){ - return codeType.isNoCode(); - } - - /** - * cleanCode cleans away all the tags inside code, decodes encoded characters, and replaces special characters. - * Example: - * {{...}} - * Outcome: - * {{...}} - * @param styleTagsInsideCode the collected style tags - * @return cleaned code - */ - private void cleanCode(StringBuffer buf, List styleTagsInsideCode){ - int startIndex = this.startIndex; - if(styleTagsInsideCode.size()>0){ - StringBuffer sb = new StringBuffer(); - for (Tag t : styleTagsInsideCode) { - sb.append(buf.substring(startIndex, t.startIndex)); - startIndex = t.endIndex; - } - sb.append(buf.substring(startIndex, endIndex)); - if(type != TagType.END){ - cleanCodeContent(sb); - }else{ - this.content = new StringBuffer(sb.toString()); - this.startIndex = 0; - this.endIndex = content.length(); - } - return; - } - if(type != TagType.END){ - cleanCodeContent(buf.subSequence(startIndex, endIndex)); - }else{ - this.content = new StringBuffer(buf.subSequence(startIndex, endIndex)); - this.startIndex = 0; - this.endIndex = content.length(); - } - - } - - private void cleanCodeContent(CharSequence cnt) { - String content = cnt.toString(); - content = content.replace("<", "<").replace(">", ">"); - content = content.replace("–", "-").replace("&", "&"); - content = content.replace("?.", "."); - content = singleQuotesEncodedRegex.matcher(doubleQuotesEncodedRegex.matcher(content).replaceAll("\"")).replaceAll("'"); - this.content = new StringBuffer(content); - this.startIndex = 0; - this.endIndex = content.length(); - } - - /** - * write attr value - */ - public void attr(String attrName, String value) { - value = StringEscapeUtils.escapeXml10(value); - AttrParse ap = parseAttr(0); - while(ap!=null){ - if(ap.content.substring(ap.coords[0], ap.coords[1]).equals(attrName)){ - //found the attr - ap.content = ap.content.replace(ap.content.substring(ap.coords[2], ap.coords[3]), value); - this.content = new StringBuffer(ap.content); - startIndex = 0; - endIndex = ap.content.length(); - return; - } - if(ap.coords[3] != 0){ - ap = parseAttr(ap.coords[3]); - }else{ - ap = parseAttr(ap.coords[1]); - } - } - String content = toString(); - content = content.replace(name, name+" "+attrName+"=\""+value+"\""); - this.content = new StringBuffer(content); - startIndex = 0; - endIndex = content.length(); - } - - /** - * read attr value - */ - public String attr(String name){ - AttrParse ap = parseAttr(0); - while(ap!=null){ - if(ap.content.substring(ap.coords[0], ap.coords[1]).equals(name)){ - //found the attr - return StringEscapeUtils.unescapeXml(ap.content.substring(ap.coords[2], ap.coords[3])); - } - if(ap.coords[3] != 0){ - ap = parseAttr(ap.coords[3]); - }else{ - ap = parseAttr(ap.coords[1]); - } - } - return null; - } - - private class AttrParse{ - String content; - int[] coords; - } - /** - * parser for reading and writing XML attributes - * @param startAt this position - * @return the coords of the attr name and value - */ - private AttrParse parseAttr(int startAt){ - AttrParse attrParse = new AttrParse(); - attrParse.coords = new int[4]; - char currentChar = 0; - char nextChar = 0; - boolean insideAttrVal = false; - boolean insideAttrName = false; - char attrValWrapperChar = 0; - CharSequence content; - if((attrParse.content = toString()) != null){ - int size = attrParse.content.length(); - if(startAt<=0){ - startAt = name.length(); - } - for(int i = startAt; i < size; ++i){ - currentChar = attrParse.content.charAt(i); - if (i + 1 < size) { - nextChar = attrParse.content.charAt(i + 1); - } else { - nextChar = 0; - } - if(!insideAttrName && !insideAttrVal && nextChar > 0 && Character.isSpaceChar(currentChar) && Character.isLetter(nextChar)){ - insideAttrName = true; - attrParse.coords[0] = i + 1; - }else if(insideAttrName && currentChar == '='){ - insideAttrName = false; - attrParse.coords[1] = i; - if(nextChar > 0 && !Character.isSpaceChar(nextChar)){ - insideAttrVal = true; - } - } else if(insideAttrVal && attrParse.coords[2] == 0){ - if(currentChar == '\'' || currentChar == '"'){ - attrValWrapperChar = currentChar; - attrParse.coords[2] = i + 1; - }else{ - attrValWrapperChar = 0; - attrParse.coords[2] = i; - } - } else if (insideAttrVal && attrParse.coords[2] != 0 && (attrValWrapperChar == 0 && Character.isSpaceChar(currentChar) || attrValWrapperChar == currentChar)) { - attrParse.coords[3] = i; - return attrParse; - } - } - } - return null; - } - - protected boolean whiteSpacesOnly(){ - char c = 0; - for(int index = startIndex; index <= endIndex; ++index){ - c = this.content.charAt(index); - if(Character.isWhitespace(c) || Character.isSpaceChar(c)){ - continue; - } - return false; - } - return true; - } - - public int length(){ - return endIndex - startIndex; - } -} diff --git a/src/main/java/com/proxeus/xml/TagType.java b/src/main/java/com/proxeus/xml/TagType.java deleted file mode 100644 index 7bde6bd..0000000 --- a/src/main/java/com/proxeus/xml/TagType.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.proxeus.xml; - -public enum TagType { - START, // or code {% if %} - END, // or code {% endif %} - START_AND_END, // or code {% set %} - HEADER, //<?xml...?> - TEXT, //everything else -} \ No newline at end of file diff --git a/src/main/java/com/proxeus/xml/XmlTemplateHandler.java b/src/main/java/com/proxeus/xml/XmlTemplateHandler.java deleted file mode 100644 index 782388b..0000000 --- a/src/main/java/com/proxeus/xml/XmlTemplateHandler.java +++ /dev/null @@ -1,805 +0,0 @@ -package com.proxeus.xml; - -import com.proxeus.xml.reader.InputStreamReader; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.Set; - -/** - * XmlTemplateHandler is the entry point and defines the core. - * - * The InputStreamReader of this handler is charset extendable after initialization. - * While the XML is being read, this handler extends reader as soon as the charset as been found. - * - * Here a very vague description of the responsibility: - * 1. reading and structuring content to code - * 2. cleaning style/formatting tags out of the code - * 3. placing code meaningful (can be enabled/disabled via config) - * 4. fixing broken XML nodes (can be enabled/disabled via config) - * - * For more information please checkout the child classes in this packages such as Code, Node, Element or Tag. - */ -public class XmlTemplateHandler { - private final static int BUFFER_SIZE = 8192; - private InputStreamReader reader; - private StringBuffer content; - private boolean reachedEOF; - private int currentIndex; - private List<Node> codesToRelate = new ArrayList<>(80); - private List<Tag> styleTagsInsideCode = new ArrayList<>(10); - private List<Code> codesRelated = new ArrayList<>(120); - private Config config; - private Node targetNode; - private char[] code = new char[3]; - private int[] codePos = new int[3]; - private Node rootNode; - private Charset charset = null; - //enables code escape feature - private final static String verbatim = "verbatim"; - - /** - * helper for finding the root node containing code - * to prevent from compiling unnecessary huge XML without code - */ - private Node firstCodeNode = null; - private Node lastCodeNode = null; - - public XmlTemplateHandler(Config config, InputStream inStream) throws Exception { - this(config, inStream, BUFFER_SIZE*10); - } - - public XmlTemplateHandler(Config config, InputStream inStream, long fileSize) throws Exception { - this.config = config; - this.content = new StringBuffer(fileSize<=0?BUFFER_SIZE*10:(int)fileSize); - this.reader = new InputStreamReader(inStream, BUFFER_SIZE); - rootNode = parse(); - } - - public boolean containsCode(){ - return rootNode != null && codesRelated.size()>0; - } - - /** - * Fixes code structures that are cutting across. - * Fixes code relations that have different parents. - */ - public void fixCodeStructures() throws Exception { - if (rootNode != null) { - boolean removeEmptyXMLWrappersAroundCode = config.HasRemoveEmptyXMLWrappersAroundCodeEntries(); - Code firstMacroCode = null; - if (removeEmptyXMLWrappersAroundCode || config.FixCodeByFindingTheNextCommonParent) { - Iterator<Code> codeIterator = codesRelated.iterator(); - Code code = null; - while (codeIterator.hasNext()) { - code = codeIterator.next(); - if(firstMacroCode == null && code.isMacroBlock()){ - firstMacroCode = code; - } - fixCode(removeEmptyXMLWrappersAroundCode, code); - } - } - if(firstMacroCode != null){ - //to support simple macro usage by {{macros.function...}} - //and to recognize it via *macros.* so we can remove the empty wrappers safely on {{..}} too - //the removal is import to support inline paragraph templates - firstMacroCode.doMacroImport(); - } - if (config.Fix_XMLTags) { - fixXMLElements(rootNode); - } - } - } - - /** - * Parse the input. - * @return root node - */ - private Node parse() throws Exception { - currentIndex = 0; - readMore();//initial read to fill the buffer - List<Node> nodes = new ArrayList<>(200); - Tag tag = null; - Node rootNode = null; - boolean ignoreCode = false; - if((tag = nextTag(ignoreCode, false)) != null){ - targetNode = rootNode = new Node(tag); - //expected <?xml version="1.0" encoding="UTF-8"?> - //if such a header is not provided, there could be encoding issues - if(tag.type == TagType.HEADER){ - String encoding = rootNode.attr("encoding"); - if(encoding != null){ - encoding = encoding.trim(); - if(Charset.isSupported(encoding)){ - charset = Charset.forName(encoding); - reader.initCharset(charset); - } - } - //to prevent from any node specific actions on the header - rootNode.type = ElementType.TEXT; - } - } - if(rootNode == null){ - throw new Exception("could'n parse a root node"); - } - Node childNode; - - while ((tag = nextTag(ignoreCode, false)) != null) { - if (tag.type == TagType.START_AND_END) { - childNode = new Node(tag); - targetNode.addChild(childNode); - if (tag.isCode()) { - childNode.interestingForLoopBack = false; - //adding it directly to the related ones as we are not going to look for a related block - codesRelated.add(new Code(tag.codeType, childNode)); - mightBeFirst(childNode); - lastCodeNode = childNode; - } - } else if (tag.type == TagType.START) { - childNode = new Node(tag); - targetNode.addChild(childNode); - if (tag.isCode()) { - if(tag.name.equals(verbatim)){ - ignoreCode = true; - } - //might need to look after this node if we get the corresponding end tag - codesToRelate.add(childNode); - mightBeFirst(childNode); - } else { - //a xml start tag, add it to the loop back as we need to find the corresponding end tag and make it the new target node - //as we need to add the upcoming children to the correct parent - nodes.add(childNode); - targetNode = childNode; - } - } else if (tag.type == TagType.END) { - Node loopNode = null; - if (tag.isCode()) { - //handle code relations independent from xml nodes as they are probably cutting across - boolean handled = false; - Node endCode = new Node(null); - endCode.setEnd(tag); - targetNode.addChild(endCode); - boolean isIf = tag.name.equals("if"); - Code targetCode = new Code(tag.codeType, endCode); - //loop back to find the corresponding start node - //for special cases like if-else, we need to find n related nodes - for (int i = codesToRelate.size() - 1; i > -1; --i) { - loopNode = codesToRelate.get(i); - if (loopNode.interestingForLoopBack && loopNode.hasNoEndTag()) { - if (isIf) { - if (loopNode.name().matches("if|elseif|else")) { - loopNode.interestingForLoopBack = false; - //remove from the code loop back list as we won't need it anymore - //codesToRelate.remove(loopNode); - //prepend the next related node before endif, else, elseif or if - targetCode.prepend(loopNode); - if ("if".equals(loopNode.name())) { - //break prepending with the if as this is the last one belonging to this very family - handled = true; - break; - } - } - } else if (tag.name.equals(loopNode.name())) { - loopNode.interestingForLoopBack = false; - //remove from the code loop back list as we won't need it anymore - //codesToRelate.remove(loopNode); - //prepend the next related node before the corresponding end node for any code block pair like {% for %}..{% endfor %} - targetCode.prepend(loopNode); - handled = true; - break; - } - } - } - lastCodeNode = endCode; - if(handled){ - if(tag.name.equals(verbatim)){ - ignoreCode = false; - } - //found the relations for this targetCode, add it to the codesRelated list for fixing patterns that are cutting across and so on - codesRelated.add(targetCode); - }else{ - //this will cause an exception during compilation, trying to fix this will lead to unexpected behaviours - //just add it to the unrelated code list although we are not going to do anything with it - //might need it in a later version for anything... - endCode.interestingForLoopBack = false; - codesToRelate.add(endCode); - } - } else { - int foundIndex = -1; - for (int i = nodes.size() - 1; i > -1; --i) { - loopNode = nodes.get(i); - if (loopNode.interestingForLoopBack && loopNode.hasNoEndTag() && tag.name.equals(loopNode.name())) { - //fount the start node containing the start tag that belongs to this end tag - loopNode.setEnd(tag); - //ensure this tag is not going to be the parent of any element anymore - loopNode.interestingForLoopBack = false; - //as this node is closed now, we need to switch the targetNode node to the parent node that is still looking for an end tag - setTargetNodeToOuterWithNoEndTagNode(loopNode); - foundIndex = i; - break; - } - } - if (foundIndex > -1) { - // now set all nodes without an end tag to failed and remove them from the loop back, starting at the index where the start tag was found - // as we won't need them anymore for loop back's - ListIterator<Node> nodeIterator = nodes.listIterator(foundIndex); - while (nodeIterator.hasNext()) { - loopNode = nodeIterator.next(); - if (loopNode.hasNoEndTag()) { - //ensure this tag is not going to be the parent of any element anymore - loopNode.interestingForLoopBack = false; - } - nodeIterator.remove(); - } - } else { - Node endTagWithoutStartTag = new Node(null); - endTagWithoutStartTag.setEnd(tag); - endTagWithoutStartTag.interestingForLoopBack = false; - targetNode.addChild(endTagWithoutStartTag); - } - } - } - } - - ListIterator<Node> nodeIterator = codesToRelate.listIterator(); - while (nodeIterator.hasNext()) { - childNode = nodeIterator.next(); - if (childNode.interestingForLoopBack && childNode.hasNoEndTag() && childNode.start.type == TagType.START) { - childNode.interestingForLoopBack = false; - //assume it is code like {% set ... %} without ending block - //if it is another kind of code, it will throw errors during compilation anyway - childNode.start.type = TagType.START_AND_END; - childNode.moveChildsToParentAtTheSamePosition(); - codesRelated.add(new Code(childNode.start.codeType, childNode)); - nodeIterator.remove(); - } - } - codesToRelate.clear(); - if(lastCodeNode == null && firstCodeNode != null){ - lastCodeNode = firstCodeNode; - } - return rootNode; - } - - private void mightBeFirst(Node n){ - if(firstCodeNode == null){ - firstCodeNode = n; - } - } - - /** - * Find the next correct parent that will contain the upcoming children while reading. - */ - private void setTargetNodeToOuterWithNoEndTagNode(Node maybeTarget) { - targetNode = maybeTarget; - while (targetNode.parent != null) { - if (targetNode.type != ElementType.CODE && targetNode.interestingForLoopBack && targetNode.hasNoEndTag()) { - return; - } - targetNode = targetNode.parent; - } - } - - /** - * Loop recursively through the DOM and check/fix broken XML tags. - * @param root element - */ - private void fixXMLElements(Element root) { - ListIterator<Element> iterator = root.children.listIterator(); - while (iterator.hasNext()) { - Element ele = iterator.next(); - if (ele.type == ElementType.XML) { - fixXMLElement(ele); - if (ele.hasChildren()) { - fixXMLElements(ele); - } - } - } - } - - /** - * Fix the provided XML element. - * @param ele the might need to be fixed - */ - private void fixXMLElement(Element ele) { - if (ele.hasNoEndTag()) { - if (config.Fix_RemoveXMLStartTagsWithoutEndTags) { - ele.removeThisElementButKeepTheChildren(); - } else { - ele.createEndTag(); - } - } else if (ele.hasNoStartTag()) { - if (config.Fix_RemoveXMLEndTagsWithoutStartTags) { - ele.removeThisElementButKeepTheChildren(); - } else { - ele.createStartTag(); - } - } - } - - /** - * Fix code that would break the XML structure after compilation, if we would leave it as is. - * @param removeEmptyXMLWrappersAroundCode whether to do further checks for removal or not - * @param code that we fix if neccessary - */ - private void fixCode(boolean removeEmptyXMLWrappersAroundCode, Code code) { - if (removeEmptyXMLWrappersAroundCode && code.shouldRemoveEmptyXMLWrappersAroundThisCode()) { - for(Node codeNode : code.relations){ - codeNode.removeEmptyXMLWrappers(config.RemoveEmptyXMLWrappersAroundCode); - } - } - - //try complicated fixes only on code blocks or blocks who doesn't have the same parent - //code with one relation are either bad written blocks or single blocks - if(code.isComment || code.relations.size()==1 || code.haveTheSameParent()){ - return; - } - //try to wrap feature is only supported for usual blocks with a staring and an ending code - //assuming size == 2 is {%start%}...{%endstart%} - if(code.relations.size()==2 && config.HasTryToWrapXMLTagWithCodeFor(code.relations.get(0).name())){ - code.tryToWrapXMLTag( - config.TryToWrapXMLTagWithCode.get(code.relations.get(0).name()), - config.TrialCountForWrappingTagWithCode); - } - if (config.FixCodeByFindingTheNextCommonParent) { - code.moveToCommonParent(config); - } - } - - /** - * nextTag provides the next tag from the current position. - * - * Text content is handled internally if breakOnText is false. - * @param ignoreCode whether to start ignoring or not. Code is only being ignored if wrapped with {% verbatim %} .. ignored code .. {% endverbatim %} - * @param breakOnText false means it adds the text content silently to the targetNode, true means it breaks the lookup if it reaches a text element with null - * @return the parsed tag. The tag can be <any>, </any>, <any/>, {{any..}}, {% any ..%} or {# any ..#} . - */ - private Tag nextTag(boolean ignoreCode, boolean breakOnText) throws Exception { - int startIndex = -1; - int slashIndex = 0; - int exclamationMarkIndex = -1; - int questionMark1Index = -1; - int questionMark2Index = -1; - int equalitySign = -1; - char openAttrQuote = 0; - boolean insideAttrVal = false; - ElementType currentType = ElementType.TEXT; - Tag t = null; - for (;hasMore(currentIndex); ++currentIndex) { - char cc = content.charAt(currentIndex); - char nc; - if (hasMore(currentIndex + 1)) { - nc = content.charAt(currentIndex + 1); - } else { - nc = 0; - } - if (currentType == ElementType.CODE) { - //parse code - if (cc == '}' || cc == '%' || cc == '#') { - if (code[2] == '%' && cc == '}' && code[0] == '{' && code[1] == '%' && codePos[2] + 1 == indexWithoutStyleTagsBetweenCodeChars(codePos[2], styleTagsInsideCode)) { - ++currentIndex; - t = new Tag(CodeType.CodeBlock, styleTagsInsideCode, content, startIndex, currentIndex, TagType.START); - } else if (code[2] == '}' && cc == '}' && code[0] == '{' && code[1] == '{' && codePos[2] + 1 == indexWithoutStyleTagsBetweenCodeChars(codePos[2], styleTagsInsideCode)) { - ++currentIndex; - t = new Tag(CodeType.Output, styleTagsInsideCode, content, startIndex, currentIndex, TagType.START_AND_END); - } else if (code[2] == '#' && cc == '}' && code[0] == '{' && code[1] == '#' && codePos[2] + 1 == indexWithoutStyleTagsBetweenCodeChars(codePos[2], styleTagsInsideCode)) { - ++currentIndex; - t = new Tag(CodeType.Comment, styleTagsInsideCode, content, startIndex, currentIndex, TagType.START_AND_END); - } else { - code[2] = cc; - codePos[2] = currentIndex; - } - if (t != null && t.isCode()) { - if(ignoreCode && (t.codeType != CodeType.CodeBlock || !t.name.equals(verbatim))){ - //escape code inside {% verbatim %} code {% endverbatim %} - styleTagsInsideCode.clear(); - currentIndex = startIndex = codePos[0]; - currentType = ElementType.TEXT; - continue; - } - if(styleTagsInsideCode.size()>0){ - Tag firstNoneSpaceTag = styleTagsInsideCode.get(0); - Tag lastStyleTagInsideCode = styleTagsInsideCode.get(styleTagsInsideCode.size()-1); - if (firstNoneSpaceTag != null && firstNoneSpaceTag.type == TagType.END - || (lastStyleTagInsideCode != null && lastStyleTagInsideCode.type == TagType.START)) { - //must have close - int currInd = currentIndex; - Tag endTagOutSideCode = nextTag(ignoreCode, true); - if (endTagOutSideCode == null || endTagOutSideCode.isCode() || (endTagOutSideCode.type == TagType.END && targetNode.name().equals(endTagOutSideCode.name))) { - //reset index - currentIndex = currInd; - } else { - //skip this tag and reorganize targetNode to ensure it is well formed - if(targetNode.parent!= null){ - Node tn = targetNode; - tn.moveChildsToParentAtTheSamePosition(); - setTargetNodeToOuterWithNoEndTagNode(tn.parent); - tn.remove(); - } - } - } - //gc help - styleTagsInsideCode.clear(); - } - return t; - } - }else if (cc == '<' && (nc == '/' || Character.isLetter(nc))) { - //if start or end tag, it has to be a style tag inside code - //collect it separately - Tag dirtyStyleTag = nextTag(ignoreCode, false); - if (dirtyStyleTag != null) { - styleTagsInsideCode.add(dirtyStyleTag); - --currentIndex; - } - } - } else if (currentType == ElementType.XML) { - if (cc == '/') { - slashIndex = currentIndex; - } else if (cc == '=') { - if (equalitySign == -1) { - equalitySign = currentIndex; - } - } else if (cc != '"' && cc != '\'') { - if (cc == '>' && !insideAttrVal) { - t = null; - if (questionMark1Index - 1 != startIndex && questionMark2Index + 1 != currentIndex && exclamationMarkIndex - 1 != startIndex) { - if (slashIndex + 1 != currentIndex && slashIndex - 1 != startIndex) { - ++currentIndex; - t = new Tag(content, startIndex, currentIndex, TagType.START); - } else if (slashIndex - 1 == startIndex) { - ++currentIndex; - t = new Tag(content, startIndex, currentIndex, TagType.END); - } else if (slashIndex + 1 == currentIndex) { - ++currentIndex; - t = new Tag(content, startIndex, currentIndex, TagType.START_AND_END); - } - } else { - ++currentIndex; - t = new Tag(content, startIndex, currentIndex, TagType.HEADER); - } - return t; - } - if (cc == '?' && (startIndex == currentIndex - 1 || nc == '>')) { - if (questionMark1Index == -1) { - questionMark1Index = currentIndex; - } else if (questionMark2Index == -1) { - questionMark2Index = currentIndex; - } - } else if (cc == '!' && startIndex == currentIndex - 1) { - exclamationMarkIndex = currentIndex; - } - } else if (equalitySign + 1 == currentIndex) { - openAttrQuote = cc; - insideAttrVal = true; - } else if (cc == openAttrQuote && (nc == '>' || nc == '/' || Character.isWhitespace(nc) || Character.isSpaceChar(nc))) { - openAttrQuote = 0; - insideAttrVal = false; - } - } else if (cc == '<') { - if (startIndex != -1) { - if(breakOnText){ - return null; - } - createTextElement(startIndex, currentIndex); - } - startIndex = currentIndex; - slashIndex = 0; - exclamationMarkIndex = -1; - questionMark1Index = -1; - questionMark2Index = -1; - equalitySign = -1; - openAttrQuote = 0; - insideAttrVal = false; - currentType = ElementType.XML; - //for code - } else if (cc == '{'){ - int currIndexForReset = currentIndex; - CodeResult cr = nextCharWithoutStyleTags(ignoreCode, true); - //make sure {%, {# and {{ are next to each other by skipping style tags between the first and the second char that look like "{<dirtystyletag>{" - if((cr.nextChar == '{' || cr.nextChar == '%' || cr.nextChar == '#') && currIndexForReset + 1 == indexWithoutStyleTagsBetweenCodeChars(currIndexForReset, cr.styleTagsInsideCode)){ - if (startIndex != -1) { - if(breakOnText){ - return null; - } - createTextElement(startIndex, currIndexForReset); - } - if(cr.styleTagsInsideCode!= null){ - styleTagsInsideCode = cr.styleTagsInsideCode; - cr.styleTagsInsideCode = null; - }else{ - styleTagsInsideCode.clear(); - } - startIndex = currIndexForReset; - slashIndex = 0; - exclamationMarkIndex = -1; - questionMark1Index = -1; - questionMark2Index = -1; - equalitySign = -1; - openAttrQuote = 0; - insideAttrVal = false; - currentType = ElementType.CODE; - - code[0] = cc; - code[1] = cr.nextChar; - code[2] = 0; - codePos[0] = currIndexForReset; - codePos[1] = cr.nextCharIndex; - codePos[2] = -1; - continue; - } - //reset because of nextCharWithoutStyleTags - currentIndex = currIndexForReset; - if(startIndex == -1){ - startIndex = currentIndex; - currentType = ElementType.TEXT; - } - } else if (startIndex == -1) { - startIndex = currentIndex; - currentType = ElementType.TEXT; - } - } - - return null; - } - - /** - * This method prevents from compiling unnecessary parts of the XML which are very heavy but do not contain any code. - * - * Retrieves the root node containing code pieces, like: - * <a> - * <b> <----- root node containing code - * <c> - * {{..}} - * </c> - * <c> - * {%if%}..{%endif%} - * {{..}} - * </c> - * </b> - * </a> - * @return the root node containing code - */ - public Node getRootNodeContainingCode(){ - if(firstCodeNode == null){ - return null; - } - return new Code(CodeType.CodeBlock, firstCodeNode, lastCodeNode).findTheCommonParent(); - } - - /** - * Find code element by name - * @return list of the findings - */ - public List<Element> findCodeElementsByName(String nameRegex) { - List<Element> codeElements = new ArrayList<>(); - for(Code code : codesRelated){ - for(Node relatedCode : code.relations){ - if(relatedCode.name().matches(nameRegex)){ - codeElements.add(relatedCode); - } - } - } - return codeElements; - } - - /** - * Find code by name. - * @return the list of the findings - */ - public List<Code> findCodeByName(String nameRegex) { - List<Code> codeElements = new ArrayList<>(); - for(Code code : codesRelated){ - for(Node relatedCode : code.relations){ - if(relatedCode.name().matches(nameRegex)){ - codeElements.add(code); - break; - } - } - } - return codeElements; - } - - /** - * Find vars with prefix. - * @param varPrefix can be null or "" - * @return the variable set - */ - public Set<String> findVars(String varPrefix) throws Exception { - VarParser varParser = new VarParser(varPrefix); - findVars(varParser); - return varParser.Vars(); - } - - /** - * Find vars. - * @param varParser will be filled with the vars - */ - public void findVars(VarParser varParser) throws Exception { - for(Code code : codesRelated){ - if(code.isComment){ - continue; - } - for(Node relatedCode : code.relations){ - if(!relatedCode.isEndTagOnly()){ - varParser.Parse(relatedCode.toString()); - } - } - } - } - - public List<Code> codes(){ - return codesRelated; - } - - /** - * Find elements by name. - */ - public List<Element> findElementsByName(String name) throws Exception { - return rootNode.findElementByName(name); - } - - /** - * Look ahead helper class - */ - private class CodeResult { - char nextChar; - int nextCharIndex; - List<Tag> styleTagsInsideCode; - } - - /** - * Look ahead for the next char without tags. Tags are being collected in #styleTagsInsideCode. - * @param ignoreCode true if we are inside a verbatim block - * @param breakOnText true if we should break on text element - * @return the findings - */ - private CodeResult nextCharWithoutStyleTags(boolean ignoreCode, boolean breakOnText) throws Exception { - CodeResult cr = new CodeResult(); - for (++currentIndex;hasMore(currentIndex); ++currentIndex) { - cr.nextChar = content.charAt(currentIndex); - cr.nextCharIndex = currentIndex; - char nc; - if (hasMore(currentIndex + 1)) { - nc = content.charAt(currentIndex + 1); - } else { - nc = 0; - } - //if start or end tag, it has to be a style tag inside code - if (cr.nextChar == '<' && (nc == '/' || Character.isLetter(nc))) { - //collect it separately - Tag dirtyStyleTag = nextTag(ignoreCode, breakOnText); - if(dirtyStyleTag == null){ - break; - } - if(cr.styleTagsInsideCode==null){ - cr.styleTagsInsideCode = new ArrayList<>(2); - } - cr.styleTagsInsideCode.add(dirtyStyleTag); - --currentIndex; - }else{ - break; - } - } - return cr; - } - - /** - * hasMore checks the content buffer if it is higher than the current index. - * If we reached the end of the current buffer, it loads more. - * If we reached the end of the file, it returns false. - * @param currentIndex calc from this index - * @return true if index is not at the end of the buffer or if we can load more. False if we reached the end. - */ - private boolean hasMore(int currentIndex) throws Exception { - if(currentIndex<content.length()){ - return true; - } - if(reachedEOF) { - return false; - } - readMore(); - return hasMore(currentIndex); - } - - private char[] readBuffer = new char[BUFFER_SIZE]; - /** - * readMore fills the main buffer to keep the process flowing - */ - public void readMore() throws Exception { - int len = reader.read(readBuffer); - if(len == -1){ - reachedEOF = true; - return; - } - content.append(readBuffer, 0, len); - } - - /** - * Calculate the index by skipping style tags, so we can tell if for example the first '{' is followed by '%'. - * @param startIndex start calculation from this index - * @param styleTagsInsideCode the style tags that have been collected so far - * @return the index without style tags - */ - private int indexWithoutStyleTagsBetweenCodeChars(int startIndex, List<Tag> styleTagsInsideCode) { - if(styleTagsInsideCode != null){ - int indexWithoutStyleTags = currentIndex; - for (Tag t : styleTagsInsideCode) { - if(t.startIndex>startIndex){ - indexWithoutStyleTags -= t.endIndex - t.startIndex; - } - } - return indexWithoutStyleTags; - } - return currentIndex; - } - - /** - * Creates a text element and adds it silently to the target node. - */ - private void createTextElement(int startIndex, int currentIndex) { - targetNode.addChild(new Element(new Tag(content, startIndex, currentIndex, TagType.TEXT))); - } - - public int length(){ - if(rootNode!=null){ - return rootNode.length(); - } - return 0; - } - - public String toString(){ - if(rootNode != null){ - StringBuilder sb = new StringBuilder(length()); - rootNode.toString(sb); - return sb.toString(); - } - return ""; - } - - public void toString(StringBuilder sb){ - if(rootNode != null){ - rootNode.toString(sb); - } - } - - public InputStream toInputStream(){ - if(rootNode != null){ - StringBuilder sb = new StringBuilder(length()); - rootNode.toString(sb); - return new ByteArrayInputStream(sb.toString().getBytes(charset)); - } - return null; - } - - public void toOutputStream(OutputStream outputStream) throws IOException { - if(rootNode != null){ - rootNode.toOutputStream(outputStream, charset); - } - } - - public Charset getCharset(){ - return charset; - } - - /** - * help gc - */ - public void free(){ - reader = null; - content = null; - codesToRelate = null; - styleTagsInsideCode = null; - codesRelated = null; - config = null; - targetNode = null; - rootNode = null; - } - -} diff --git a/src/main/java/com/proxeus/xml/processor/NoOpEventProcessor.java b/src/main/java/com/proxeus/xml/processor/NoOpEventProcessor.java new file mode 100644 index 0000000..8c2aae2 --- /dev/null +++ b/src/main/java/com/proxeus/xml/processor/NoOpEventProcessor.java @@ -0,0 +1,17 @@ +package com.proxeus.xml.processor; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamException; + +public class NoOpEventProcessor implements XMLEventProcessor { + @Override + public void process(XMLEventReader reader, XMLEventWriter writer) throws XMLStreamException, IllegalStateException { + if(reader == null || writer == null){ + return; + } + while(reader.hasNext()){ + writer.add(reader.nextEvent()); + } + } +} diff --git a/src/main/java/com/proxeus/xml/processor/XMLEventBuffer.java b/src/main/java/com/proxeus/xml/processor/XMLEventBuffer.java new file mode 100644 index 0000000..7fec053 --- /dev/null +++ b/src/main/java/com/proxeus/xml/processor/XMLEventBuffer.java @@ -0,0 +1,130 @@ +package com.proxeus.xml.processor; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.XMLEvent; +import java.util.Iterator; +import java.util.LinkedList; + +public class XMLEventBuffer implements XMLEventReadWriter { + private LinkedList<XMLEvent> events = new LinkedList<>(); + private XMLEventReader reader; + + public XMLEventBuffer() { + + } + + public XMLEventBuffer(XMLEventReader reader) { + this.reader = reader; + } + + public Iterator<XMLEvent> interator() { + return events.iterator(); + } + + @Override + public void flush() throws XMLStreamException { + + } + + @Override + public void close() throws XMLStreamException { + events = null; + } + + // Writer + @Override + public void add(XMLEvent event) throws XMLStreamException { + events.add(event); + } + + @Override + public void add(XMLEventReader reader) throws XMLStreamException { + while (reader.hasNext()) { + events.add(reader.nextEvent()); + } + } + + @Override + public String getPrefix(String uri) throws XMLStreamException { + // Not implemented + return ""; + } + + @Override + public void setPrefix(String prefix, String uri) throws XMLStreamException { + // Not implemented + } + + @Override + public void setDefaultNamespace(String uri) throws XMLStreamException { + // Not implemented + } + + @Override + public void setNamespaceContext(NamespaceContext context) throws XMLStreamException { + // Not implemented + } + + @Override + public NamespaceContext getNamespaceContext() { + // Not implemented + return null; + } + + // Reader + @Override + public XMLEvent nextEvent() throws XMLStreamException { + emptyReader(); + return events.removeFirst(); + } + + @Override + public boolean hasNext() { + emptyReader(); + return events.size() > 0; + } + + @Override + public Object next() { + emptyReader(); + return events.removeFirst(); + } + + @Override + public XMLEvent peek() throws XMLStreamException { + return events.peekFirst(); + } + + @Override + public String getElementText() throws XMLStreamException { + // Not implemented + return ""; + } + + @Override + public XMLEvent nextTag() throws XMLStreamException { + // Not implemented + return null; + } + + @Override + public Object getProperty(String name) throws IllegalArgumentException { + // Not implemented + return null; + } + + private void emptyReader() { + if (this.reader != null) { + while (reader.hasNext()) { + try { + add(reader.nextEvent()); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + } + this.reader = null; + } + } +} diff --git a/src/main/java/com/proxeus/xml/processor/XMLEventProcessor.java b/src/main/java/com/proxeus/xml/processor/XMLEventProcessor.java new file mode 100644 index 0000000..d2bea72 --- /dev/null +++ b/src/main/java/com/proxeus/xml/processor/XMLEventProcessor.java @@ -0,0 +1,10 @@ +package com.proxeus.xml.processor; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamException; + +public interface XMLEventProcessor { + @SuppressWarnings({"unchecked", "null"}) + void process(XMLEventReader reader, XMLEventWriter writer) throws XMLStreamException, IllegalStateException; +} diff --git a/src/main/java/com/proxeus/xml/processor/XMLEventProcessorChain.java b/src/main/java/com/proxeus/xml/processor/XMLEventProcessorChain.java new file mode 100644 index 0000000..601489b --- /dev/null +++ b/src/main/java/com/proxeus/xml/processor/XMLEventProcessorChain.java @@ -0,0 +1,46 @@ +package com.proxeus.xml.processor; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamException; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +public class XMLEventProcessorChain implements XMLEventProcessor { + + private List<XMLEventProcessor> processors = new LinkedList<>(); + + public XMLEventProcessorChain(XMLEventProcessor... processors) { + this.processors.addAll(Arrays.asList(processors)); + if (processors.length == 0) { + this.processors.add(new NoOpEventProcessor()); + } + } + + public void addProcessor(XMLEventProcessor... processors) { + this.processors.addAll(Arrays.asList(processors)); + } + + @Override + public void process(XMLEventReader input, XMLEventWriter output) throws XMLStreamException, IllegalStateException { + try { + + XMLEventReadWriter in = new XMLEventBuffer(input); + XMLEventReadWriter out = null; + + for (XMLEventProcessor processor : processors) { + out = new XMLEventBuffer(); + processor.process(in, out); + in = out; + } + + while (out.hasNext()) { + output.add(out.nextEvent()); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/com/proxeus/xml/processor/XMLEventReadWriter.java b/src/main/java/com/proxeus/xml/processor/XMLEventReadWriter.java new file mode 100644 index 0000000..7721ff9 --- /dev/null +++ b/src/main/java/com/proxeus/xml/processor/XMLEventReadWriter.java @@ -0,0 +1,7 @@ +package com.proxeus.xml.processor; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; + +public interface XMLEventReadWriter extends XMLEventReader, XMLEventWriter { +} diff --git a/src/main/java/com/proxeus/xml/processor/XMLEventSink.java b/src/main/java/com/proxeus/xml/processor/XMLEventSink.java new file mode 100644 index 0000000..de179a8 --- /dev/null +++ b/src/main/java/com/proxeus/xml/processor/XMLEventSink.java @@ -0,0 +1,54 @@ +package com.proxeus.xml.processor; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.XMLEvent; + +public class XMLEventSink implements XMLEventWriter { + @Override + public void flush() throws XMLStreamException { + + } + + @Override + public void close() throws XMLStreamException { + + } + + @Override + public void add(XMLEvent event) throws XMLStreamException { + + } + + @Override + public void add(XMLEventReader reader) throws XMLStreamException { + + } + + @Override + public String getPrefix(String uri) throws XMLStreamException { + return null; + } + + @Override + public void setPrefix(String prefix, String uri) throws XMLStreamException { + + } + + @Override + public void setDefaultNamespace(String uri) throws XMLStreamException { + + } + + @Override + public void setNamespaceContext(NamespaceContext context) throws XMLStreamException { + + } + + @Override + public NamespaceContext getNamespaceContext() { + return null; + } +} diff --git a/src/main/java/com/proxeus/xml/reader/InputStreamReader.java b/src/main/java/com/proxeus/xml/reader/InputStreamReader.java deleted file mode 100644 index b00a297..0000000 --- a/src/main/java/com/proxeus/xml/reader/InputStreamReader.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.proxeus.xml.reader; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; - -/** - * XmlStreamReader makes it possible to read with the plain inputStream without a charset. - * After the charset is read from the file it can be set to this reader to extend readability. - */ -public class InputStreamReader { - private StreamDecoder sd; - private boolean correctCharsetHasBeenSet = false; - private Charset charset; - private InputStream in; - private int bufferSize; - - public InputStreamReader(InputStream in) { - this.in = in; - this.bufferSize = 1024; - } - public InputStreamReader(InputStream in, int bufferSize) { - this.in = in; - this.bufferSize = bufferSize; - } - - public InputStreamReader(InputStream in, Charset charset, int bufferSize) { - this.in = in; - this.charset = charset; - this.correctCharsetHasBeenSet = true; - this.bufferSize = bufferSize; - sd = new StreamDecoder(in, charset, bufferSize); - } - - public Charset getCharset() { - return charset; - } - - /** - * Set the charset after it was read from the content header. - * This method can be called only once. - */ - public void initCharset(Charset chrset) { - if (correctCharsetHasBeenSet) { - return; - } - correctCharsetHasBeenSet = true; - charset = chrset; - sd = new StreamDecoder(in, charset, bufferSize); - } - - public int read() throws IOException { - if (correctCharsetHasBeenSet) { - return sd.read(); - } - return in.read(); - } - - public int read(char cbuf[]) throws IOException { - return read(cbuf, 0, cbuf.length); - } - - public int read(char cbuf[], int offset, int length) throws IOException { - if (correctCharsetHasBeenSet) { - return sd.read(cbuf, offset, length); - } - //just read one byte as long as we don't have the correct charset - length = read(); - if(length == -1){ - return -1; - } - cbuf[0] = (char) length; - return 1; - } - - public boolean ready() throws IOException { - return sd.ready(); - } - - public void close() throws IOException { - sd.close(); - } -} diff --git a/src/main/java/com/proxeus/xml/reader/StreamDecoder.java b/src/main/java/com/proxeus/xml/reader/StreamDecoder.java deleted file mode 100644 index 42cf689..0000000 --- a/src/main/java/com/proxeus/xml/reader/StreamDecoder.java +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.proxeus.xml.reader; - -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.channels.FileChannel; -import java.nio.channels.ReadableByteChannel; -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CoderResult; -import java.nio.charset.CodingErrorAction; - -/** - * StreamDecoder is a copy of java source from https://github.com/frohoff/jdk8u-jdk/blob/master/src/share/classes/sun/nio/cs/StreamDecoder.java. - * The reason for copying was the private access of the constructors. - * - * I removed all the synchronized blocks as it will be always touched by one thread in our case and - * I made modifications to extend the reader with this as soon as we have read the charset. - */ -public class StreamDecoder { - private volatile boolean isOpen = true; - - private void ensureOpen() throws IOException { - if (!isOpen) - throw new IOException("Stream closed"); - } - - // In order to handle surrogates properly we must never try to produce - // fewer than two characters at a time. If we're only asked to return one - // character then the other is saved here to be returned later. - // - private boolean haveLeftoverChar = false; - private char leftoverChar; - - public int read() throws IOException { - // Return the leftover char, if there is one - if (haveLeftoverChar) { - haveLeftoverChar = false; - return leftoverChar; - } - - // Convert more bytes - char cb[] = new char[2]; - int n = read(cb, 0, 2); - switch (n) { - case -1: - return -1; - case 2: - leftoverChar = cb[1]; - haveLeftoverChar = true; - // FALL THROUGH - case 1: - return cb[0]; - default: - assert false : n; - return -1; - } - } - - public int read(char cbuf[], int offset, int length) throws IOException { - int off = offset; - int len = length; - ensureOpen(); - if ((off < 0) || (off > cbuf.length) || (len < 0) || - ((off + len) > cbuf.length) || ((off + len) < 0)) { - throw new IndexOutOfBoundsException(); - } - if (len == 0) - return 0; - - int n = 0; - - if (haveLeftoverChar) { - // Copy the leftover char into the buffer - cbuf[off] = leftoverChar; - off++; - len--; - haveLeftoverChar = false; - n = 1; - if ((len == 0) || !implReady()) - // Return now if this is all we can produce w/o blocking - return n; - } - - if (len == 1) { - // Treat single-character array reads just like read() - int c = read(); - if (c == -1) - return (n == 0) ? -1 : n; - cbuf[off] = (char) c; - return n + 1; - } - - return n + implRead(cbuf, off, off + len); - } - - public boolean ready() throws IOException { - ensureOpen(); - return haveLeftoverChar || implReady(); - } - - public void close() throws IOException { - if (!isOpen) - return; - implClose(); - isOpen = false; - } - - private boolean isOpen() { - return isOpen; - } - - - // -- Charset-based stream decoder impl -- - - // In the early stages of the build we haven't yet built the NIO native - // code, so guard against that by catching the first UnsatisfiedLinkError - // and setting this flag so that later attempts fail quickly. - // - private static volatile boolean channelsAvailable = true; - - private static FileChannel getChannel(FileInputStream in) { - if (!channelsAvailable) - return null; - try { - return in.getChannel(); - } catch (UnsatisfiedLinkError x) { - channelsAvailable = false; - return null; - } - } - - private Charset cs; - private CharsetDecoder decoder; - private ByteBuffer bb; - - // Exactly one of these is non-null - private InputStream in; - private ReadableByteChannel ch; - - public StreamDecoder(InputStream in, Charset cs, int maxBufferSize) { - this(in, - cs.newDecoder() - .onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE), maxBufferSize); - } - - StreamDecoder(InputStream in, CharsetDecoder dec, int maxBufferSize) { - this.cs = dec.charset(); - this.decoder = dec; - - // This path disabled until direct buffers are faster - if (false && in instanceof FileInputStream) { - ch = getChannel((FileInputStream) in); - if (ch != null) - bb = ByteBuffer.allocateDirect(maxBufferSize); - } - if (ch == null) { - this.in = in; - this.ch = null; - bb = ByteBuffer.allocate(maxBufferSize); - } - bb.flip(); // So that bb is initially empty - } - - private int readBytes() throws IOException { - bb.compact(); - try { - if (ch != null) { - // Read from the channel - int n = ch.read(bb); - if (n < 0) - return n; - } else { - // Read from the input stream, and then update the buffer - int lim = bb.limit(); - int pos = bb.position(); - assert (pos <= lim); - int rem = (pos <= lim ? lim - pos : 0); - assert rem > 0; - int n = in.read(bb.array(), bb.arrayOffset() + pos, rem); - if (n < 0) - return n; - if (n == 0) - throw new IOException("Underlying input stream returned zero bytes"); - assert (n <= rem) : "n = " + n + ", rem = " + rem; - bb.position(pos + n); - } - } finally { - // Flip even when an IOException is thrown, - // otherwise the stream will stutter - bb.flip(); - } - - int rem = bb.remaining(); - assert (rem != 0) : rem; - return rem; - } - - int implRead(char[] cbuf, int off, int end) throws IOException { - - // In order to handle surrogate pairs, this method requires that - // the invoker attempt to read at least two characters. Saving the - // extra character, if any, at a higher level is easier than trying - // to deal with it here. - assert (end - off > 1); - - CharBuffer cb = CharBuffer.wrap(cbuf, off, end - off); - if (cb.position() != 0) - // Ensure that cb[0] == cbuf[off] - cb = cb.slice(); - - boolean eof = false; - while(true) { - CoderResult cr = decoder.decode(bb, cb, eof); - if (cr.isUnderflow()) { - if (eof) - break; - if (!cb.hasRemaining()) - break; - if ((cb.position() > 0) && !inReady()) - break; // Block at most once - int n = readBytes(); - if (n < 0) { - eof = true; - if ((cb.position() == 0) && (!bb.hasRemaining())) - break; - decoder.reset(); - } - continue; - } - if (cr.isOverflow()) { - assert cb.position() > 0; - break; - } - cr.throwException(); - } - - if (eof) { - // ## Need to flush decoder - decoder.reset(); - } - - if (cb.position() == 0) { - if (eof) - return -1; - assert false; - } - return cb.position(); - } - - private boolean inReady() { - try { - return (((in != null) && (in.available() > 0)) - || (ch instanceof FileChannel)); // ## RBC.available()? - } catch (IOException x) { - return false; - } - } - - boolean implReady() { - return bb.hasRemaining() || inReady(); - } - - void implClose() throws IOException { - if (ch != null) - ch.close(); - else - in.close(); - } - -} \ No newline at end of file diff --git a/src/main/java/com/proxeus/xml/template/CleanEmptyElementProcessor.java b/src/main/java/com/proxeus/xml/template/CleanEmptyElementProcessor.java new file mode 100644 index 0000000..a3b3cfd --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/CleanEmptyElementProcessor.java @@ -0,0 +1,83 @@ +package com.proxeus.xml.template; + +import com.proxeus.xml.processor.XMLEventProcessor; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLEventFactory; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.util.LinkedList; +import java.util.List; + +public class CleanEmptyElementProcessor implements XMLEventProcessor { + private List<QName> emptyElementToRemove; + LinkedList<XMLEvent> queue = new LinkedList<>(); + + private XMLEventFactory eventFactory = XMLEventFactory.newInstance(); + + public CleanEmptyElementProcessor(List<QName> emptyElementToRemove) { + this.emptyElementToRemove = emptyElementToRemove; + } + + @Override + public void process(XMLEventReader reader, XMLEventWriter writer) throws XMLStreamException, IllegalStateException { + while (reader.hasNext()) { + XMLEvent event = reader.nextEvent(); + switch (event.getEventType()) { + case XMLEvent.START_DOCUMENT: + writer.add(event); + writer.add(eventFactory.createCharacters(System.lineSeparator())); + break; + case XMLEvent.START_ELEMENT: + StartElement s = event.asStartElement(); + queue.offer(s); + continue; + case XMLEvent.CHARACTERS: + Characters c = event.asCharacters(); + if (!c.isIgnorableWhiteSpace()) { + flush(c, writer); + } + continue; + case XMLEvent.END_ELEMENT: + EndElement e = event.asEndElement(); + if (queue.isEmpty()) { + flush(e, writer); + continue; + } + + if (!emptyElementToRemove.contains(e.getName())) { + flush(e, writer); + continue; + } + + XMLEvent previous = queue.peekLast(); + if (!previous.isStartElement() || !previous.asStartElement().getName().equals(e.getName())) { + flush(e, writer); + continue; + } + + queue.removeLast(); + + continue; + default: + flush(event, writer); + } + } + } + + private void flush(XMLEvent event, XMLEventWriter writer) { + queue.offer(event); + while (!queue.isEmpty()) { + try { + writer.add(queue.pollFirst()); + } catch (Exception e) { + // pollFirst only throws exception if the queue is empty which cannot happen here. + } + } + } +} diff --git a/src/main/java/com/proxeus/xml/template/DefaultTemplateHandler.java b/src/main/java/com/proxeus/xml/template/DefaultTemplateHandler.java new file mode 100644 index 0000000..1a7e2c0 --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/DefaultTemplateHandler.java @@ -0,0 +1,140 @@ +package com.proxeus.xml.template; + +import com.proxeus.xml.processor.XMLEventProcessor; +import org.apache.log4j.Logger; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.stream.*; +import javax.xml.stream.events.StartDocument; +import javax.xml.stream.events.XMLEvent; +import java.io.*; +import java.nio.charset.Charset; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; + +import static java.nio.charset.StandardCharsets.UTF_8; + + +public class DefaultTemplateHandler implements TemplateHandler { + + private Logger log = Logger.getLogger(this.getClass()); + private TemplateXMLEventWriter events; + private XMLEventProcessor processor; + private TemplateRenderer renderer; + + public DefaultTemplateHandler(XMLEventProcessor processor, TemplateRenderer renderer) { + this.events = new TemplateXMLEventWriter(); + this.processor = processor; + this.renderer = renderer; + } + + @Override + public void process(InputStream input) throws Exception { + // First, create a new XMLInputFactory + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + // Setup a new eventReader + try { + XMLEventReader reader = inputFactory.createXMLEventReader(input); + processor.process(reader, events); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void render(OutputStream output, Map<String, Object> data) throws Exception { + ByteArrayOutputStream xmlOutput = new ByteArrayOutputStream(); + + XMLEventWriter writer = XMLOutputFactory.newInstance().createXMLEventWriter(xmlOutput); + Charset charset = UTF_8; + Iterator<XMLEvent> it = events.interator(); + while (it.hasNext()) { + XMLEvent e = it.next(); + if (e.isStartDocument()) { + StartDocument sd = (StartDocument) e; + charset = Charset.forName(sd.getCharacterEncodingScheme()); + } + writer.add(e); + } + + if (data == null){ + data = Collections.emptyMap(); + } + InputStream input = new ByteArrayInputStream(xmlOutput.toByteArray()); + this.renderer.render(input, output, data, charset); + } + + @Override + public Charset getCharset() { + return Charset.defaultCharset(); + } + + @Override + public void toOutputStream(OutputStream output) throws IOException { + + } + + @Override + public void free() { + + } + + private class TemplateXMLEventWriter implements XMLEventWriter { + private LinkedList<XMLEvent> events = new LinkedList<>(); + + public Iterator<XMLEvent> interator() { + return events.iterator(); + } + + @Override + public void flush() throws XMLStreamException { + + } + + @Override + public void close() throws XMLStreamException { + events = null; + } + + @Override + public void add(XMLEvent event) throws XMLStreamException { + events.add(event); + } + + @Override + public void add(XMLEventReader reader) throws XMLStreamException { + while (reader.hasNext()) { + events.add(reader.nextEvent()); + } + } + + @Override + public String getPrefix(String uri) throws XMLStreamException { + // Not implemented + return ""; + } + + @Override + public void setPrefix(String prefix, String uri) throws XMLStreamException { + // Not implemented + } + + @Override + public void setDefaultNamespace(String uri) throws XMLStreamException { + // Not implemented + } + + @Override + public void setNamespaceContext(NamespaceContext context) throws XMLStreamException { + // Not implemented + } + + @Override + public NamespaceContext getNamespaceContext() { + // Not implemented + return null; + } + } +} diff --git a/src/main/java/com/proxeus/xml/template/ExtractorXMLEvent.java b/src/main/java/com/proxeus/xml/template/ExtractorXMLEvent.java new file mode 100644 index 0000000..979d088 --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/ExtractorXMLEvent.java @@ -0,0 +1,129 @@ +package com.proxeus.xml.template; + +import com.proxeus.xml.template.parser.ParserState; +import com.proxeus.xml.template.parser.TagType; + +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.io.Writer; + +public class ExtractorXMLEvent implements XMLEvent { + + private XMLEvent event; + private ParserState state; + private TagType tagType; + private int blockId; + + public ExtractorXMLEvent(XMLEvent event, ParserState state, TagType tagType, int blockId) { + this.event = event; + this.state = state; + this.tagType = tagType; + this.blockId = blockId; + } + + public ParserState getState() { + return state; + } + + public int getBlockId() { + return blockId; + } + + public TagType getTagType() { + return tagType; + } + + public XMLEvent getEvent() { + return event; + } + + @Override + public int getEventType() { + return event.getEventType(); + } + + @Override + public Location getLocation() { + return event.getLocation(); + } + + @Override + public boolean isStartElement() { + return event.isStartElement(); + } + + @Override + public boolean isAttribute() { + return event.isAttribute(); + } + + @Override + public boolean isNamespace() { + return event.isNamespace(); + } + + @Override + public boolean isEndElement() { + return event.isEndElement(); + } + + @Override + public boolean isEntityReference() { + return event.isEntityReference(); + } + + @Override + public boolean isProcessingInstruction() { + return event.isProcessingInstruction(); + } + + @Override + public boolean isCharacters() { + return event.isCharacters(); + } + + @Override + public boolean isStartDocument() { + return event.isStartDocument(); + } + + @Override + public boolean isEndDocument() { + return event.isEndDocument(); + } + + @Override + public StartElement asStartElement() { + return event.asStartElement(); + } + + @Override + public EndElement asEndElement() { + return event.asEndElement(); + } + + @Override + public Characters asCharacters() { + return event.asCharacters(); + } + + @Override + public QName getSchemaType() { + return event.getSchemaType(); + } + + @Override + public void writeAsEncodedUnicode(Writer writer) throws XMLStreamException { + event.writeAsEncodedUnicode(writer); + } + + public String toString() { + return event.toString(); + } + +} diff --git a/src/main/java/com/proxeus/xml/template/NoOpTemplateRenderer.java b/src/main/java/com/proxeus/xml/template/NoOpTemplateRenderer.java new file mode 100644 index 0000000..abf54a5 --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/NoOpTemplateRenderer.java @@ -0,0 +1,15 @@ +package com.proxeus.xml.template; + +import org.apache.commons.io.IOUtils; + +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.util.Map; + +public class NoOpTemplateRenderer implements TemplateRenderer { + @Override + public void render(InputStream input, OutputStream output, Map<String, Object> data, Charset charset) throws Exception { + IOUtils.copy(input, output); + } +} diff --git a/src/main/java/com/proxeus/xml/template/TemplateExtractor.java b/src/main/java/com/proxeus/xml/template/TemplateExtractor.java new file mode 100644 index 0000000..387827f --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/TemplateExtractor.java @@ -0,0 +1,329 @@ +package com.proxeus.xml.template; + +import com.proxeus.xml.processor.XMLEventProcessor; +import com.proxeus.xml.template.parser.ParserState; +import com.proxeus.xml.template.parser.TagType; +import com.proxeus.xml.template.parser.TemplateParser; +import org.apache.log4j.Logger; + +import javax.xml.stream.XMLEventFactory; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.util.LinkedList; +import java.util.ListIterator; + +import static com.proxeus.xml.template.parser.TagType.CODE; +import static com.proxeus.xml.template.parser.TagType.NONE; + +/** + * This class process JTwig template code island (http://jtwig.org/documentation/reference/syntax/code-islands) + * located in the XML text nodes and transform the XML document to a JTwig template. + * <p> + * <p> + * First, we need to ensure that code islands do not contain any XML tags: + * * XML elements entirely inside a code island are deleted, + * * XML tags opening inside an island are push after the end of the code island, + * * XML tags closing inside code island are pull forward before the code island. + * + * <pre>{@Code + * {%...........................%} {% ......%} + * <a>...</a> + * <b>..........</b> <c>.......</c> + * <d>...</d> <e>..................</e> + * + * will result in : + * + * {% ..........................%} {% ......%} + * <a>...</a> + * <b>...</b> <c>....</c> + * <e>....</e> + * }</pre> + * + * + * <pre>{@Code + * If an element span several code islands, we need to split them: + * + * {%..........%} {%..........%} {%.........%} + * <a>......................................................................</a> + * + * + * will results in: + * + * {%..........%} {%..........%} {%.........%} + * <a>...</a> <a>...</a> <a>...</a> <a>...</a> + * }</pre> + * + * <pre>{@Code + * If an element span an output or a comment island, we do not need to split it: + * + * {{..........}} {%..........%} {#.........#} + * <a>......................................................................</a> + * + * will results in: + * + * {{..........}} {%..........%} {#.........#} + * <a>.........................</a> <a>........................</a> + * }</pre> + */ +public class TemplateExtractor implements XMLEventProcessor { + + private Logger log = Logger.getLogger(this.getClass()); + private TemplateParser parser; + + private LinkedList<ExtractorXMLEvent> tmpQueue; + private LinkedList<ExtractorXMLEvent> elementStack; + private LinkedList<ExtractorXMLEvent> resultQueue; + + private XMLEventFactory eventFactory = XMLEventFactory.newInstance(); + + public TemplateExtractor(TemplateParser parser) { + this.parser = parser; + this.tmpQueue = new LinkedList<>(); + this.elementStack = new LinkedList<>(); + this.resultQueue = new LinkedList<>(); + } + + @Override + @SuppressWarnings({"unchecked", "null"}) + public void process(XMLEventReader reader, XMLEventWriter writer) throws XMLStreamException, IllegalStateException { + while (reader.hasNext()) { + XMLEvent event = reader.nextEvent(); + processEvent(event); + } + + for(ExtractorXMLEvent event : resultQueue){ + writer.add(event.getEvent()); + } + } + + + private void processEvent(XMLEvent event) { + log("PROCESS EVENT<%s>\n", eventType(event)); + switch (event.getEventType()) { + case XMLEvent.START_DOCUMENT: + pushResult(event); + pushResult(eventFactory.createCharacters(System.lineSeparator())); + break; + case XMLEvent.END_DOCUMENT: + if (this.parser.getState() != ParserState.XML) { + throw new IllegalStateException("Template code island not terminated"); + } + pushResult(event); + break; + case XMLEvent.START_ELEMENT: + switch (parser.getState()) { + case XML: + pushResult(event); + + break; + case MAYBE_START_DELIMITER: + case MAYBE_END_DELIMITER: + case TEMPLATE: + pushTmp(event); + } + break; + case XMLEvent.END_ELEMENT: + EndElement end = event.asEndElement(); + switch (parser.getState()) { + case XML: + pushResult(event); + break; + case MAYBE_START_DELIMITER: + case MAYBE_END_DELIMITER: + pushTmp(event); + break; + case TEMPLATE: + log("BEGIN END_ELEMENT IN TEMPLATE %s tmp: %s result: %s\n", end.getName(), tmpQueue.toString(), resultQueue.toString()); + boolean ignore = false; + // If the start element is in the template, then we remove the start and the end elements. + if (tmpQueue.size() > 0) { + ListIterator<ExtractorXMLEvent> it = tmpQueue.listIterator(tmpQueue.size()); + while (it.hasPrevious()) { + ExtractorXMLEvent e = it.previous(); + if (!e.isStartElement()) { + continue; + } + StartElement s = e.asStartElement(); + if (s.getName().equals(end.getName())) { + log("Match start tag %s\n", e.toString()); + it.remove(); + ignore = true; + break; + } + throw new IllegalStateException("XML not well formed, start and end tags do not match"); + } + } + + if (!ignore) { + // The end element is pushed before the code island + pushResult(event, ParserState.XML, NONE); + } + log("END END_ELEMENT IN TEMPLATE %s\n", end.getName()); + } + + break; + case XMLEvent.CHARACTERS: + Characters c = event.asCharacters(); + if (c.isIgnorableWhiteSpace()) { + break; + } + if (c.isCData()) { + pushResult(event); + break; + } + + + parser.onProcessQueue(s -> processTmpQueue()); + parser.onFlushCharacters(e -> flush(e.getCharacters(), e.getState(), e.getTagType())); + try { + log("PROCESS CHARACTERS -->%s<--\n", c.getData()); + parser.process(c.getData()); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + + default: + } + } + + private void log(String format, Object... args) { + log.trace(String.format("<%s> <%s> <%d> %s", parser.getState(), parser.getTagType(), parser.getBlockId(), String.format(format, args))); + } + + private void pushResult(XMLEvent event) { + pushResult(event, parser.getState(), parser.getTagType(), parser.getBlockId()); + } + + private void pushResult(XMLEvent event, ParserState state, TagType tagType) { + pushResult(event, state, tagType, parser.getBlockId()); + } + + private void pushResult(XMLEvent event, ParserState state, TagType tagType, int blockId) { + log("PUSH EVENT TO RESULT QUEUE %s -->%s<--\n", eventType(event), event.toString()); + ExtractorXMLEvent e = new ExtractorXMLEvent(event, state, tagType, blockId); + switch (e.getEvent().getEventType()) { + case XMLEvent.START_ELEMENT: + resultQueue.add(e); + elementStack.push(e); + break; + case XMLEvent.END_ELEMENT: + resultQueue.add(e); + ExtractorXMLEvent stacktHead = elementStack.pop(); + splitSpanningElement(stacktHead, e); + break; + default: + resultQueue.add(e); + } + } + + private void splitSpanningElement(ExtractorXMLEvent start, ExtractorXMLEvent end) { + log("SPLIT SPANNING ELEMENT %s %s\n", eventType(start), start.toString()); + if (start.getBlockId() == end.getBlockId()) { + return; + } + + int endIndex = resultQueue.indexOf(end); + if (endIndex == -1) { + return; + } + + ListIterator<ExtractorXMLEvent> it = resultQueue.listIterator(endIndex); + while (it.hasPrevious()) { + ExtractorXMLEvent previous = it.previous(); + if (previous == start) { + break; + } + + // The assumption is that a code island is contained in its own characters event. + // This has to be enforced by the template parser. + if (previous.getTagType() != CODE) { + continue; + } + + log("SPLIT CODE %s %s %s %s %s \n", eventType(previous), previous.toString(), previous.getState(), previous.getTagType(), previous.getBlockId()); + int blockId = previous.getBlockId(); + // Wrap the code island with </...> <...> + + it.next(); + + it.add(new ExtractorXMLEvent(clone(start.getEvent()), ParserState.XML, NONE, blockId)); + it.previous(); + it.previous(); + + blockId = it.previous().getBlockId(); + it.next(); + it.add(new ExtractorXMLEvent(clone(end.getEvent()), ParserState.XML, NONE, blockId)); + if (blockId == start.getBlockId()) { + // We closed the element in the right block. + break; + } + } + } + + private XMLEvent clone(XMLEvent event) { + switch (event.getEventType()) { + case XMLEvent.START_ELEMENT: + StartElement start = event.asStartElement(); + return eventFactory.createStartElement(start.getName(), start.getAttributes(), start.getNamespaces()); + case XMLEvent.END_ELEMENT: + EndElement end = event.asEndElement(); + return eventFactory.createEndElement(end.getName(), end.getNamespaces()); + default: + throw new IllegalStateException("not implemented"); + } + } + + private EndElement clone(EndElement s) { + return eventFactory.createEndElement(s.getName(), s.getNamespaces()); + } + + private void pushStack(XMLEvent event) { + log("PUSH EVENT TO STACK %d %s\n", event.getEventType(), event.toString()); + elementStack.push(new ExtractorXMLEvent(event, parser.getState(), parser.getTagType(), parser.getBlockId())); + } + + private void pushTmp(XMLEvent event) { + log("PUSH EVENT TO TMP QUEUE %d %s\n", event.getEventType(), event.toString()); + tmpQueue.add(new ExtractorXMLEvent(event, parser.getState(), parser.getTagType(), parser.getBlockId())); + } + + private void flush(String characters, ParserState state, TagType tagType) { + pushResult(eventFactory.createCharacters(characters)); + } + + private void processTmpQueue() { + log("BEGIN PROCESSING TMP QUEUE %s tmp: %s\n", resultQueue.toString(), tmpQueue.toString()); + if (tmpQueue.size() > 0) { + // Cloning the tmpQueue as we are re-entering the processor. + LinkedList<ExtractorXMLEvent> clone = new LinkedList<>(); + clone.addAll(tmpQueue); // + tmpQueue.clear(); + for (ExtractorXMLEvent e : clone) { + processEvent(e.getEvent()); + } + } + log("END PROCESSING TMP QUEUE %s\n", resultQueue.toString()); + } + + private String eventType(XMLEvent event) { + switch (event.getEventType()) { + case XMLEvent.START_DOCUMENT: + return "START DOCUMENT"; + case XMLEvent.END_DOCUMENT: + return "END DOCUMENT"; + case XMLEvent.START_ELEMENT: + return "START ELEMENT " + event.asStartElement().getName(); + case XMLEvent.END_ELEMENT: + return "END ELEMENT " + event.asEndElement().getName(); + case XMLEvent.CHARACTERS: + return "CHARACTERS"; + default: + return "UNKNOWN"; + } + } +} diff --git a/src/main/java/com/proxeus/xml/template/TemplateHandler.java b/src/main/java/com/proxeus/xml/template/TemplateHandler.java new file mode 100644 index 0000000..86ff91a --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/TemplateHandler.java @@ -0,0 +1,21 @@ +package com.proxeus.xml.template; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.util.Map; + + +public interface TemplateHandler { + void process(InputStream input) throws Exception; + + void render(OutputStream output, Map<String,Object> data) throws Exception; + + Charset getCharset(); + + void toOutputStream(OutputStream outputStream) throws IOException; + + void free(); + +} diff --git a/src/main/java/com/proxeus/xml/template/TemplateHandlerFactory.java b/src/main/java/com/proxeus/xml/template/TemplateHandlerFactory.java new file mode 100644 index 0000000..761b806 --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/TemplateHandlerFactory.java @@ -0,0 +1,7 @@ +package com.proxeus.xml.template; + +import com.proxeus.xml.processor.XMLEventProcessor; + +public interface TemplateHandlerFactory { + TemplateHandler newInstance(XMLEventProcessor ...processors); +} diff --git a/src/main/java/com/proxeus/xml/template/TemplateRenderer.java b/src/main/java/com/proxeus/xml/template/TemplateRenderer.java new file mode 100644 index 0000000..13ce7ba --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/TemplateRenderer.java @@ -0,0 +1,10 @@ +package com.proxeus.xml.template; + +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.util.Map; + +public interface TemplateRenderer { + void render(InputStream input, OutputStream output, Map<String, Object> data, Charset charset) throws Exception; +} diff --git a/src/main/java/com/proxeus/xml/template/TemplateVarParser.java b/src/main/java/com/proxeus/xml/template/TemplateVarParser.java new file mode 100644 index 0000000..1be997b --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/TemplateVarParser.java @@ -0,0 +1,8 @@ +package com.proxeus.xml.template; + +import java.util.Set; + +public interface TemplateVarParser { + void parse(String input); + Set<String> getVars(); +} diff --git a/src/main/java/com/proxeus/xml/template/TemplateVarParserFactory.java b/src/main/java/com/proxeus/xml/template/TemplateVarParserFactory.java new file mode 100644 index 0000000..b71d20e --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/TemplateVarParserFactory.java @@ -0,0 +1,5 @@ +package com.proxeus.xml.template; + +public interface TemplateVarParserFactory { + TemplateVarParser newInstance(); +} diff --git a/src/main/java/com/proxeus/xml/template/TemplateVarProcessor.java b/src/main/java/com/proxeus/xml/template/TemplateVarProcessor.java new file mode 100644 index 0000000..f8d9e6d --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/TemplateVarProcessor.java @@ -0,0 +1,36 @@ +package com.proxeus.xml.template; + +import com.proxeus.xml.processor.XMLEventProcessor; +import org.apache.log4j.Logger; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.XMLEvent; + +public class TemplateVarProcessor implements XMLEventProcessor { + + private Logger log = Logger.getLogger(this.getClass()); + private TemplateVarParser varParser; + + public TemplateVarProcessor(TemplateVarParser varParser) { + this.varParser = varParser; + } + + @Override + public void process(XMLEventReader reader, XMLEventWriter writer) throws XMLStreamException, IllegalStateException { + while (reader.hasNext()) { + XMLEvent event = reader.nextEvent(); + + writer.add(event); + + if(!event.isCharacters()){ + continue; + } + + Characters c = event.asCharacters(); + varParser.parse(c.getData()); + } + } +} diff --git a/src/main/java/com/proxeus/xml/template/jtwig/JTwigParser.java b/src/main/java/com/proxeus/xml/template/jtwig/JTwigParser.java new file mode 100644 index 0000000..3ab4aa1 --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/jtwig/JTwigParser.java @@ -0,0 +1,267 @@ +package com.proxeus.xml.template.jtwig; + +import com.proxeus.xml.template.parser.*; + +import javax.xml.stream.XMLStreamException; +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Set; +import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static com.proxeus.xml.template.parser.ParserState.*; +import static com.proxeus.xml.template.parser.TagType.*; + +/** + * + */ +public class JTwigParser implements TemplateParser, TemplateParserFactory { + + private ParserState state; + private TagType tagType; + private StringBuffer nextCharacters; + + private int blockCounter; + private LinkedList<Integer> blockStack; + + private Consumer<CharactersEvent> onFlushCharacters; + private Consumer<StateChangeEvent> onProcessQueue; + + private static Set<String> blockStart = new HashSet<>(Arrays.asList("if", "elseif", "else", "for", "block", "embed", "macro", "autoescape", "filter", "verbatim")); + private static Set<String> blockEnd = new HashSet<>(Arrays.asList("elseif", "else", "endif", "endfor", "endblock", "endembed", "endmacro", "endautoescape", "endfilter", "endverbatim")); + + // Block processors are JTWig tags that process content between the start and end tags. The full construct should be handled as one template element and any added XML tags should be + // push around it + private static Set<String> blockProcessor = new HashSet<>(Arrays.asList("autoescape", "filter", "verbatim")); + + + public JTwigParser() { + this.state = XML; + this.tagType = NONE; + this.nextCharacters = new StringBuffer(); + this.blockStack = new LinkedList<>(); + } + + @Override + public TemplateParser newInstance() { + return new JTwigParser(); + } + + @Override + public ParserState getState() { + return this.state; + } + + @Override + public TagType getTagType() { + return this.tagType; + } + + @Override + public int getBlockId() { + if (blockStack.size() == 0) { + return 0; + } + return blockStack.peek(); + } + + private int pushBlock() { + blockCounter++; + blockStack.push(blockCounter); + return blockCounter; + } + + private int popBlock() { + if (blockStack.size() > 0) { + blockStack.pop(); + } + return getBlockId(); + } + + @Override + public void onFlushCharacters(Consumer<CharactersEvent> onFlushCharacters) { + this.onFlushCharacters = onFlushCharacters; + } + + @Override + public void onProcessQueue(Consumer<StateChangeEvent> onProcessQueue) { + this.onProcessQueue = onProcessQueue; + } + + @Override + public void process(String characters) throws XMLStreamException { + CharacterIterator it = new StringCharacterIterator(characters); + while (it.current() != CharacterIterator.DONE) { + process(it.current()); + it.next(); + } + if (state == ParserState.XML && nextCharacters.length() > 0) { + flush(nextCharacters, state, tagType, getBlockId()); + } + } + + private void process(char c) throws XMLStreamException { + switch (this.state) { + case XML: + switch (c) { + case '{': + // We flush the current characters as the assumption to be enforced is that code islands + // must be contained in their own characters events. + flush(nextCharacters, state, tagType, getBlockId()); + stateChange(MAYBE_START_DELIMITER, NONE); + nextCharacters.append(c); + break; + default: + nextCharacters.append(c); + } + break; + case MAYBE_START_DELIMITER: + if (Character.isWhitespace(c)) { + break; + } + switch (c) { + case '%': + stateChange(TEMPLATE, CODE); + processQueue(); + nextCharacters.append(c); + break; + case '{': + stateChange(TEMPLATE, OUTPUT); + processQueue(); + nextCharacters.append(c); + break; + case '#': + stateChange(TEMPLATE, COMMENT); + processQueue(); + nextCharacters.append(c); + break; + default: + stateChange(XML, NONE); + flush(nextCharacters, state, tagType, getBlockId()); + processQueue(); + nextCharacters.append(c); + } + break; + case TEMPLATE: + if (Character.isWhitespace(c)) { + if (nextCharacters.length() == 0 || !Character.isWhitespace(nextCharacters.charAt(nextCharacters.length() - 1))) { + nextCharacters.append(' '); + } + } else { + nextCharacters.append(c); + } + switch (c) { + case '%': + if (this.tagType == CODE) { + stateChange(MAYBE_END_DELIMITER); + } + break; + case '}': + if (this.tagType == OUTPUT) { + stateChange(MAYBE_END_DELIMITER); + } + break; + case '#': + if (this.tagType == COMMENT) { + stateChange(MAYBE_END_DELIMITER); + } + break; + case '"': + stateChange(DOUBLE_QUOTE_STRING); + break; + case '\'': + stateChange(SINGLE_QUOTE_STRING); + } + break; + case DOUBLE_QUOTE_STRING: + nextCharacters.append(c); + switch (c) { + case '"': + stateChange(TEMPLATE); + } + break; + case SINGLE_QUOTE_STRING: + nextCharacters.append(c); + switch (c) { + case '\'': + stateChange(TEMPLATE); + } + break; + case MAYBE_END_DELIMITER: + switch (c) { + case '}': + stateChange(TEMPLATE); + processQueue(); + nextCharacters.append(c); + + if (tagType == CODE) { + // This ensure that the code island block id is the same as the block id of the following block. + // + // {%if ... %} ... {% endif %} + // 0 1 1 0 0 + updateBlock(nextCharacters.toString()); + } + + flush(nextCharacters, state, tagType, getBlockId()); + + stateChange(XML, NONE); + processQueue(); + + break; + default: + stateChange(TEMPLATE); + nextCharacters.append(c); + } + } + } + + private void updateBlock(String island) { + String command = extractCommand(island); + if (blockEnd.contains(command)) { + popBlock(); + } + if (blockStart.contains(command)) { + pushBlock(); + } + } + + static private Pattern commandPattern = Pattern.compile("\\{%\\W*(\\w+)(\\W|%)?.*"); + + static protected String extractCommand(String island) { + Matcher m = commandPattern.matcher(island); + if (!m.matches()) { + return ""; + } + + return m.group(1); + } + + + private void flush(StringBuffer characters, ParserState state, TagType tagType, int blockId) { + if (onFlushCharacters != null) { + onFlushCharacters.accept(new CharactersEvent(characters.toString(), state, tagType, blockId)); + } + characters.delete(0, characters.length()); + } + + private void stateChange(ParserState state) throws XMLStreamException { + stateChange(state, tagType); + } + + private void stateChange(ParserState newState, TagType newTagType) throws XMLStreamException { + this.state = newState; + this.tagType = newTagType; + } + + private void processQueue() { + if (onProcessQueue != null) { + onProcessQueue.accept(new StateChangeEvent(state, tagType, getBlockId())); + } + } + + +} diff --git a/src/main/java/com/proxeus/xml/template/jtwig/JTwigRenderer.java b/src/main/java/com/proxeus/xml/template/jtwig/JTwigRenderer.java new file mode 100644 index 0000000..f5267b9 --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/jtwig/JTwigRenderer.java @@ -0,0 +1,21 @@ +package com.proxeus.xml.template.jtwig; + +import com.proxeus.compiler.jtwig.MyJTwigCompiler; +import com.proxeus.xml.template.TemplateRenderer; +import org.apache.log4j.Logger; + +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.util.Map; + +public class JTwigRenderer implements TemplateRenderer { + private Logger log = Logger.getLogger(this.getClass()); + + private MyJTwigCompiler compiler = new MyJTwigCompiler(); + + @Override + public void render(InputStream input, OutputStream output, Map<String, Object> data, Charset charset) throws Exception { + compiler.Compile(input, data, output, charset); + } +} diff --git a/src/main/java/com/proxeus/xml/template/jtwig/JTwigTemplateHandlerFactory.java b/src/main/java/com/proxeus/xml/template/jtwig/JTwigTemplateHandlerFactory.java new file mode 100644 index 0000000..fd14afb --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/jtwig/JTwigTemplateHandlerFactory.java @@ -0,0 +1,17 @@ +package com.proxeus.xml.template.jtwig; + +import com.proxeus.compiler.jtwig.MyJTwigCompiler; +import com.proxeus.xml.processor.XMLEventProcessor; +import com.proxeus.xml.processor.XMLEventProcessorChain; +import com.proxeus.xml.template.*; + +public class JTwigTemplateHandlerFactory implements TemplateHandlerFactory { + + @Override + public TemplateHandler newInstance(XMLEventProcessor... processors) { + XMLEventProcessorChain p = new XMLEventProcessorChain(new TemplateExtractor(new JTwigParser())); + p.addProcessor(processors); + return new DefaultTemplateHandler(p, new JTwigRenderer()); + } + +} diff --git a/src/main/java/com/proxeus/xml/template/jtwig/JTwigTemplateVarParserFactory.java b/src/main/java/com/proxeus/xml/template/jtwig/JTwigTemplateVarParserFactory.java new file mode 100644 index 0000000..4ec0860 --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/jtwig/JTwigTemplateVarParserFactory.java @@ -0,0 +1,11 @@ +package com.proxeus.xml.template.jtwig; + +import com.proxeus.xml.template.TemplateVarParser; +import com.proxeus.xml.template.TemplateVarParserFactory; + +public class JTwigTemplateVarParserFactory implements TemplateVarParserFactory { + @Override + public TemplateVarParser newInstance() { + return new JTwigVarParser(""); + } +} diff --git a/src/main/java/com/proxeus/xml/VarParser.java b/src/main/java/com/proxeus/xml/template/jtwig/JTwigVarParser.java similarity index 93% rename from src/main/java/com/proxeus/xml/VarParser.java rename to src/main/java/com/proxeus/xml/template/jtwig/JTwigVarParser.java index 0575133..d06788b 100644 --- a/src/main/java/com/proxeus/xml/VarParser.java +++ b/src/main/java/com/proxeus/xml/template/jtwig/JTwigVarParser.java @@ -1,14 +1,16 @@ -package com.proxeus.xml; +package com.proxeus.xml.template.jtwig; + +import com.proxeus.xml.template.TemplateVarParser; import java.util.HashSet; import java.util.Set; import java.util.TreeSet; /** - * VarParser parses all kind of vars provided in output blocks like {{...}} or code blocks like {%...%}. + * JTwigVarParser parses all kind of vars provided in output blocks like {{...}} or code blocks like {%...%}. * It ensures the natural alphabetic order in the returned set and it is possible to filter variables by a prefix. */ -public class VarParser { +public class JTwigVarParser implements TemplateVarParser { //use TreeSet to deliver sorted vars private Set<String> vars = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); private String prefix = null; @@ -40,13 +42,14 @@ private static void addStartsWith(String reserved) { reservedWordsStartsWith.add(reserved); } - public VarParser(String varPrefix) { + public JTwigVarParser(String varPrefix) { if (varPrefix != null && varPrefix.length() > 0) { this.prefix = varPrefix; } } - public Set<String> Vars() { + @Override + public Set<String> getVars() { return vars; } @@ -55,7 +58,8 @@ public Set<String> Vars() { * * @param content must either start with {{ .. }} or with {% .. %} */ - public void Parse(String content) { + @Override + public void parse(String content) { char currentChar = 0; char nextChar = 0; boolean insideString = false; @@ -109,7 +113,7 @@ public void Parse(String content) { pipe = -1; } else { //ensure we close the inline condition - if(currentChar == ':'){ + if (currentChar == ':') { inlineCondition = false; } //found a var('s) @@ -188,4 +192,6 @@ private int isDivider(char c) { } return -1; } + + } diff --git a/src/main/java/com/proxeus/xml/template/parser/CharactersEvent.java b/src/main/java/com/proxeus/xml/template/parser/CharactersEvent.java new file mode 100644 index 0000000..324bedb --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/parser/CharactersEvent.java @@ -0,0 +1,16 @@ +package com.proxeus.xml.template.parser; + +public class CharactersEvent extends StateChangeEvent { + private String characters; + private ParserState state; + private TagType tagType; + + public CharactersEvent(String characters, ParserState state, TagType tagType, int blockId) { + super(state, tagType, blockId); + this.characters = characters; + } + + public String getCharacters() { + return characters; + } +} diff --git a/src/main/java/com/proxeus/xml/template/parser/ParserState.java b/src/main/java/com/proxeus/xml/template/parser/ParserState.java new file mode 100644 index 0000000..5f85b15 --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/parser/ParserState.java @@ -0,0 +1,13 @@ +package com.proxeus.xml.template.parser; + +public enum ParserState { + //External states + XML, + MAYBE_DELIMITER, // Either MAYBE_START_DELIMITER or MAYBE_END_DELIMITER + TEMPLATE, + // internal states + MAYBE_START_DELIMITER, + MAYBE_END_DELIMITER, + SINGLE_QUOTE_STRING, + DOUBLE_QUOTE_STRING, +} diff --git a/src/main/java/com/proxeus/xml/template/parser/StateChangeEvent.java b/src/main/java/com/proxeus/xml/template/parser/StateChangeEvent.java new file mode 100644 index 0000000..d9b83c0 --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/parser/StateChangeEvent.java @@ -0,0 +1,31 @@ +package com.proxeus.xml.template.parser; + +import static com.proxeus.xml.template.parser.ParserState.*; + +public class StateChangeEvent { + private ParserState state; + private TagType tagType; + private int blockId; + + public StateChangeEvent(ParserState state, TagType tagType, int blockId) { + this.state = state; + this.tagType = tagType; + this.blockId = blockId; + } + + public ParserState getState() { + if (state == MAYBE_START_DELIMITER || state == MAYBE_END_DELIMITER){ + return MAYBE_DELIMITER; + } + + if (state == DOUBLE_QUOTE_STRING || state ==SINGLE_QUOTE_STRING ){ + return TEMPLATE; + } + + return state; + } + + public TagType getTagType() { + return tagType; + } +} diff --git a/src/main/java/com/proxeus/xml/template/parser/TagType.java b/src/main/java/com/proxeus/xml/template/parser/TagType.java new file mode 100644 index 0000000..2c1da93 --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/parser/TagType.java @@ -0,0 +1,8 @@ +package com.proxeus.xml.template.parser; + +public enum TagType { + NONE, + CODE, + OUTPUT, + COMMENT +} diff --git a/src/main/java/com/proxeus/xml/template/parser/TemplateParser.java b/src/main/java/com/proxeus/xml/template/parser/TemplateParser.java new file mode 100644 index 0000000..ca6d99e --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/parser/TemplateParser.java @@ -0,0 +1,18 @@ +package com.proxeus.xml.template.parser; + +import javax.xml.stream.XMLStreamException; +import java.util.function.Consumer; + +public interface TemplateParser { + ParserState getState(); + + TagType getTagType(); + + int getBlockId(); + + void onFlushCharacters(Consumer<CharactersEvent> onFlushCharacters); + + void onProcessQueue(Consumer<StateChangeEvent> onProcessQueue); + + void process(String characters) throws XMLStreamException; +} diff --git a/src/main/java/com/proxeus/xml/template/parser/TemplateParserFactory.java b/src/main/java/com/proxeus/xml/template/parser/TemplateParserFactory.java new file mode 100644 index 0000000..ab1d64a --- /dev/null +++ b/src/main/java/com/proxeus/xml/template/parser/TemplateParserFactory.java @@ -0,0 +1,5 @@ +package com.proxeus.xml.template.parser; + +public interface TemplateParserFactory { + TemplateParser newInstance(); +} diff --git a/src/main/resources/conf.json b/src/main/resources/conf.json index 14b1333..c5be5e9 100644 --- a/src/main/resources/conf.json +++ b/src/main/resources/conf.json @@ -7,7 +7,7 @@ "max": 100,/** max workers **/ "timeout":"30s",/** timeout duration **/ "logConfig":{ - "level":"INFO", /** OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL **/ + "level":"TRACE", /** OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL **/ "level_console":"DEBUG", /** OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL **/ "maxFileSize": "5MB", "maxBackupIndex": 5, diff --git a/src/test/java/com/proxeus/ConfigTest.java b/src/test/java/com/proxeus/ConfigTest.java new file mode 100644 index 0000000..1d65a7d --- /dev/null +++ b/src/test/java/com/proxeus/ConfigTest.java @@ -0,0 +1,49 @@ +package com.proxeus; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class ConfigTest { + + @Test + public void create_shouldSetProperAttributesByPassingTheCorrectStructure() { + Map<String, Object> map = new HashMap<>(); + map.put("protocol", "anyProtocol"); + map.put("host", "anyHost"); + map.put("tmpFolder", "anyFolder"); + map.put("port", 8081); + + final Config config = Config.create(map); + + assertEquals("anyProtocol", config.getProtocol()); + assertEquals("anyHost", config.getHost()); + assertEquals("anyFolder", config.getTmpFolder()); + assertEquals(8081, config.getPort().intValue()); + } + + @Test + public void parseDurationToMillis_shouldConvertCorrectly() { + final Map<String, Long> expectedResponsesMap = new HashMap<>(); + expectedResponsesMap.put("2s", 2000l); + expectedResponsesMap.put("500s", 500000l); + expectedResponsesMap.put("1m", 60000l); + expectedResponsesMap.put("1h", 3600000l); + expectedResponsesMap.put("24h", 86400000l); + + for(String input : expectedResponsesMap.keySet()) { + long response = Config.parseDurationToMillis(input); + long expected = expectedResponsesMap.get(input); + + assertEquals(expected, response); + } + } + + @Test(expected = RuntimeException.class) + public void parseDurationToMillis_shouldReturnRuntimeExceptionOnUnknownSyntax() { + Config.parseDurationToMillis("no-syntax"); + } +} \ No newline at end of file diff --git a/src/test/java/com/proxeus/IntegrationTest.java b/src/test/java/com/proxeus/IntegrationTest.java new file mode 100644 index 0000000..09b07ec --- /dev/null +++ b/src/test/java/com/proxeus/IntegrationTest.java @@ -0,0 +1,4 @@ +package com.proxeus; + +public interface IntegrationTest { +} diff --git a/src/test/java/com/proxeus/document/AssetFileTest.java b/src/test/java/com/proxeus/document/AssetFileTest.java new file mode 100644 index 0000000..af14c06 --- /dev/null +++ b/src/test/java/com/proxeus/document/AssetFileTest.java @@ -0,0 +1,56 @@ +package com.proxeus.document; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +public class AssetFileTest { + + private static File tmpDir; + + + @BeforeClass + public static void setTmpDir() { + String property = "java.io.tmpdir"; + String tempDir = System.getProperty(property); + tmpDir = new File(tempDir); + } + + @Test + public void testFindLocalFile() { + String file = "/img.jpg"; + AssetFile newAssetFile = AssetFile.find(file, tmpDir); + + Assert.assertEquals(new File(String.format("%s/img.jpg", tmpDir)), newAssetFile.src); + } + + @Test + public void testFindEmbeddedFile() { + String lexicalXSDBase64Binary = " iVBORw0KGgoAAAANSUhEUgAAAAUA"; + + String png = String.format("data:image/png;base64,%s\n" + + " AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO\n" + + " 9TXL0Y4OHwAAAABJRU5ErkJggg==", lexicalXSDBase64Binary); + + + byte[] expectedBytes = javax.xml.bind.DatatypeConverter.parseBase64Binary(lexicalXSDBase64Binary); + + AssetFile newAssetFile = AssetFile.find(png, tmpDir); + + + byte[] assetBytes; + try { + assetBytes = Files.readAllBytes(newAssetFile.src.toPath()); + } catch (IOException e) { + e.printStackTrace(); + Assert.fail(); + return; + } + + Assert.assertArrayEquals(expectedBytes, assetBytes); + } +} diff --git a/src/test/java/com/proxeus/document/FileResultTest.java b/src/test/java/com/proxeus/document/FileResultTest.java new file mode 100644 index 0000000..32b3b5d --- /dev/null +++ b/src/test/java/com/proxeus/document/FileResultTest.java @@ -0,0 +1,18 @@ +package com.proxeus.document; + +import org.junit.Test; + +import static org.mockito.Mockito.*; + +public class FileResultTest { + + @Test + public void release_shouldReleaseTemplate() { + Template template = mock(Template.class); + + final FileResult fileResult = new FileResult(template); + fileResult.release(); + + verify(template, times(1)).release(); + } +} \ No newline at end of file diff --git a/src/test/java/com/proxeus/document/odt/ODTManifestProcessorTest.java b/src/test/java/com/proxeus/document/odt/ODTManifestProcessorTest.java new file mode 100644 index 0000000..66053b3 --- /dev/null +++ b/src/test/java/com/proxeus/document/odt/ODTManifestProcessorTest.java @@ -0,0 +1,66 @@ +package com.proxeus.document.odt; + +import com.proxeus.document.AssetFile; +import com.proxeus.xml.processor.XMLEventProcessor; +import com.proxeus.xml.template.DefaultTemplateHandler; +import com.proxeus.xml.template.NoOpTemplateRenderer; +import com.proxeus.xml.template.jtwig.JTwigParser; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.io.*; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.Queue; +import java.util.stream.Collectors; + +@RunWith(Parameterized.class) +public class ODTManifestProcessorTest { + private String test; + + public ODTManifestProcessorTest (String test) { + this.test = test; + } + + @Parameterized.Parameters(name = "{index}: {0}") + public static Iterable<? extends Object> tests() { + return Arrays.asList( + "manifest" + ); + } + + @Test + public void test() { + try { + + Queue<AssetFile> assetFiles = new LinkedList<>(); + AssetFile assetFile = new AssetFile(); + assetFile.orgZipPath = "Pictures/10000000000000850000006377498356141931B6.jpg"; + assetFile.newZipPath = "foobar.jpg"; + + assetFiles.offer(assetFile); + XMLEventProcessor processor = new ODTManifestProcessor(assetFiles); + + InputStream input = getClass().getClassLoader().getResourceAsStream(test + ".xml"); + DefaultTemplateHandler handler = new DefaultTemplateHandler(processor, new NoOpTemplateRenderer()); + handler.process(input); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + + handler.render(output, null); + + InputStream expected = JTwigParser.class.getClassLoader().getResourceAsStream(test + "_processed.xml"); + Assert.assertEquals(convert(expected, Charset.defaultCharset()), output.toString()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private String convert(InputStream inputStream, Charset charset) throws IOException { + try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, charset))) { + return br.lines().collect(Collectors.joining(System.lineSeparator())); + } + } +} \ No newline at end of file diff --git a/src/test/java/com/proxeus/document/odt/TemplateCompilerTest.java b/src/test/java/com/proxeus/document/odt/TemplateCompilerTest.java new file mode 100644 index 0000000..6113961 --- /dev/null +++ b/src/test/java/com/proxeus/document/odt/TemplateCompilerTest.java @@ -0,0 +1,103 @@ +package com.proxeus.document.odt; + +import com.proxeus.Application; +import com.proxeus.Config; +import com.proxeus.document.FileResult; +import com.proxeus.document.Template; +import com.proxeus.document.TemplateCompiler; +import com.proxeus.document.TemplateFormatter; +import com.proxeus.office.libre.exe.Extension; +import com.proxeus.util.zip.EntryFileFilter; +import com.proxeus.util.zip.Zip; +import com.proxeus.xml.template.jtwig.JTwigTemplateHandlerFactory; +import com.proxeus.xml.template.jtwig.JTwigTemplateVarParserFactory; +import org.apache.commons.io.IOUtils; +import org.junit.Assert; +import org.junit.Test; + +import java.io.*; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +/** + * Test the compiler up to formatting. Generate the ODT file whose content is then compared with the expected result. + */ +public class TemplateCompilerTest { + + @Test + public void testCompile() throws Exception { + + Config config = Application.init(); + TemplateCompiler templateCompiler = new TemplateCompiler(config.getTmpFolder(), new TestTemplateFormatter(), new JTwigTemplateHandlerFactory(), new JTwigTemplateVarParserFactory()); + + InputStream inputStream = new ByteArrayInputStream(createZip()); + + FileResult result = templateCompiler.compile(Template.fromZip(inputStream, "pdf"), false); + + OutputStream content= new ByteArrayOutputStream(); + Zip.extract(result.target, new EntryFileFilter() { + public void next(ZipEntry entry, ZipFile zf) throws Exception { + if (entry.getName().startsWith("content.xml")) { + IOUtils.copy(zf.getInputStream(entry), content); + } + } + }); + InputStream expected = getClass().getClassLoader().getResourceAsStream("content_noif_fixed_cleaned.xml"); + Assert.assertEquals(convert(expected, Charset.defaultCharset()), content.toString()); + } + + + private byte[] createZip() throws Exception { + List<String> srcFiles = Arrays.asList("simple_noif_template.odt", "simple.json"); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + ZipOutputStream zipOut = new ZipOutputStream(os); + for (String srcFile : srcFiles) { + System.out.println(srcFile); + InputStream fis = getClass().getClassLoader().getResourceAsStream(srcFile); + ZipEntry zipEntry = new ZipEntry(srcFile); + zipOut.putNextEntry(zipEntry); + + byte[] bytes = new byte[1024]; + int length; + while ((length = fis.read(bytes)) >= 0) { + zipOut.write(bytes, 0, length); + } + fis.close(); + } + zipOut.close(); + + return os.toByteArray(); + } + + private String convert(InputStream inputStream, Charset charset) throws IOException { + try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, charset))) { + return br.lines().collect(Collectors.joining(System.lineSeparator())); + } + } + + private class TestTemplateFormatter implements TemplateFormatter { + + @Override + public String Convert(File src, File dst, String format, boolean restart) throws Exception { + Assert.assertEquals(false, restart); + Assert.assertEquals("pdf", format); + + Assert.assertEquals(src.getParentFile(), dst.getParentFile()); + Assert.assertEquals("tmpl.odt", src.getName()); + Assert.assertEquals("final", dst.getName()); + Files.copy(src.toPath(), dst.toPath()); + return "test"; + } + + @Override + public Extension getExtension(String os) { + return null; + } + } +} diff --git a/src/test/java/com/proxeus/document/odt/img/DecimalAndUnitTest.java b/src/test/java/com/proxeus/document/odt/img/DecimalAndUnitTest.java new file mode 100644 index 0000000..850b982 --- /dev/null +++ b/src/test/java/com/proxeus/document/odt/img/DecimalAndUnitTest.java @@ -0,0 +1,74 @@ +package com.proxeus.document.odt.img; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Project: document-service + * User: awerffeli + * Date: 06.03.20 + * Time: 13:40 + **/ +public class DecimalAndUnitTest { + + + @Test + public void testToString() { + DecimalAndUnit decimalAndUnit = new DecimalAndUnit(); + decimalAndUnit.number = 1; + decimalAndUnit.unit = "cm"; + + + Assert.assertEquals("1.0cm", decimalAndUnit.toString()); + } + + @Test + public void testGetWithDPI() { + DecimalAndUnit decimalAndUnit = new DecimalAndUnit(); + decimalAndUnit.number = 1; + decimalAndUnit.unit = "cm"; + + + double withDPI = 0; + try { + withDPI = decimalAndUnit.getWithDPI(2.0); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + + Assert.assertEquals(5.08, withDPI, 0); + + + decimalAndUnit.unit = "in"; + try { + withDPI = decimalAndUnit.getWithDPI(2.0); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + + Assert.assertEquals(2.0, withDPI, 0); + + + decimalAndUnit.unit = "pt"; + try { + withDPI = decimalAndUnit.getWithDPI(2.0); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + + Assert.assertEquals(0.027777777777777776, withDPI, 0); + + + decimalAndUnit.unit = ""; + try { + decimalAndUnit.getWithDPI(2.0); + } catch (Exception e) { + //success + return; + } + Assert.fail(); + } +} diff --git a/src/test/java/com/proxeus/document/odt/img/ImageAdjusterRunnableTest.java b/src/test/java/com/proxeus/document/odt/img/ImageAdjusterRunnableTest.java new file mode 100644 index 0000000..f5b2b20 --- /dev/null +++ b/src/test/java/com/proxeus/document/odt/img/ImageAdjusterRunnableTest.java @@ -0,0 +1,56 @@ +package com.proxeus.document.odt.img; + +import com.proxeus.document.AssetFile; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.File; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * Project: document-service + * User: awerffeli + * Date: 06.03.20 + * Time: 13:59 + **/ +public class ImageAdjusterRunnableTest { + + private static File tmpDir; + + + @BeforeClass + public static void setTmpDir() { + String property = "java.io.tmpdir"; + String tempDir = System.getProperty(property); + tmpDir = new File(tempDir); + } + + @Test + public void testRun() { + Queue<AssetFile> assetFiles = new ConcurrentLinkedQueue<>(); + Queue<Exception> exceptions = new ConcurrentLinkedQueue<>(); + + ImageSettings imageSettings = new ImageSettings("1", "2", "3", "4cm", "5cm", tmpDir, assetFiles); + imageSettings.assetFilesToInclude = new ConcurrentLinkedQueue<>(); + + String png = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAASCAYAAABrXO8xAAAKumlDQ1BJQ0MgUHJvZmlsZQAASImVlwdUk8kWx+f70hstAQEpoTdBepUSeiiCdLARkpCEEmJCULGhIiq4FkREQF3RVYqCawFkLUgRC4uCvW6QRUBdFws21LwPeYTd985777z/OZP5nZs7996ZM3PO/QAgf2SJRBmwCgCZwmxxVJAvPSExiY77HUCADIhACQAWWyJiREaGAURT89/1/g7ijeim9USsf///v0qVw5WwAYAiEU7hSNiZCJ9ChowtEmcDgCpB7EZLs0UT3IwwTYwUiHD3BPMmWTbBKZP87rtPTJQfAGg8AHgyiyXmAUCmIXZ6DpuHxCE7Imwr5AiECHMQ9mLzWchMPoTwrMzMrAm+gbB5yl/i8P4WM0URk8XiKXhyL9+F9xdIRBms5f/ncfxvZWZIp3KYIoPMFwdHTeRDzuxeelaogoUpcyOmWMCZrGmC+dLg2ClmS/ySppjD8g9VrM2YGzbFqYJApiJONjNmirmSgOgpFmdFKXKliv0YU8wST+eVpscq7HwuUxE/lx8TP8U5gri5UyxJjw6d9vFT2MXSKEX9XGGQ73TeQMXeMyV/2a+AqVibzY8JVuydNV0/V8iYjilJUNTG4foHTPvEKvxF2b6KXKKMSIU/NyNIYZfkRCvWZiMXcnptpOIM01ghkVMMBCAcsAA7m7sse6J4vyzRcrGAx8+mM5BXxaUzhWybWXR7W3tbACbe6OQVGL3+/e1BWqrTtg1DyJU+JZfLG6dtzE4ATmwGgISftplZAqDUDsBlIVsqzpm0oSd+MMjLVwY0oAX0gBEwB9bAHjgDD+ADAkAIiAAxIBEsAmzAB5lADJaClWAtKABFYDvYBcrBfnAQVINj4ARoAmfBRXAJXAM3wG3wEMjAIHgBRsF7MA5BEA6iQFRIC9KHTCAryB5yhbygACgMioISoWSIBwkhKbQSWg8VQcVQOXQAqoF+hs5AF6ErUC90H+qHRqA30GcYBZNhGqwLm8KzYVeYAYfCMfBCmAcvgXPhfHgrXAZXwUfhRvgifA2+DcvgF/AYCqBIKA2UAcoa5YryQ0WgklCpKDFqNaoQVYqqQtWjWlBdqJsoGeol6hMai6ai6WhrtAc6GB2LZqOXoFejt6DL0dXoRnQH+ia6Hz2K/oahYHQwVhh3DBOTgOFhlmIKMKWYw5jTmE7Mbcwg5j0Wi9XAmmFdsMHYRGwadgV2C3YvtgHbiu3FDmDHcDicFs4K54mLwLFw2bgC3B7cUdwFXB9uEPcRT8Lr4+3xgfgkvBC/Dl+Kr8Wfx/fhh/DjBBWCCcGdEEHgEJYTthEOEVoI1wmDhHGiKtGM6EmMIaYR1xLLiPXETuIj4lsSiWRIciPNIwlIeaQy0nHSZVI/6RNZjWxJ9iMvIEvJW8lHyK3k++S3FArFlOJDSaJkU7ZSaijtlCeUj0pUJRslphJHaY1ShVKjUp/SK2WCsokyQ3mRcq5yqfJJ5evKL1UIKqYqfiosldUqFSpnVO6qjKlSVe1UI1QzVbeo1qpeUR1Ww6mZqgWocdTy1Q6qtasNUFFUI6oflU1dTz1E7aQO0rA0MxqTlkYroh2j9dBG1dXUHdXj1JepV6ifU5dpoDRMNZgaGRrbNE5o3NH4PEN3BmMGd8bmGfUz+mZ80Jyp6aPJ1SzUbNC8rflZi64VoJWutUOrSeuxNlrbUnue9lLtfdqd2i9n0mZ6zGTPLJx5YuYDHVjHUidKZ4XOQZ1unTFdPd0gXZHuHt123Zd6Gno+eml6JXrn9Ub0qfpe+gL9Ev0L+s/p6nQGPYNeRu+gjxroGAQbSA0OGPQYjBuaGcYarjNsMHxsRDRyNUo1KjFqMxo11jcON15pXGf8wIRg4mrCN9lt0mXywdTMNN50o2mT6bCZphnTLNeszuyROcXc23yJeZX5LQushatFusVeixuWsKWTJd+ywvK6FWzlbCWw2mvVOwszy22WcFbVrLvWZGuGdY51nXW/jYZNmM06myabV7ONZyfN3jG7a/Y3WyfbDNtDtg/t1OxC7NbZtdi9sbe0Z9tX2N9yoDgEOqxxaHZ47WjlyHXc53jPieoU7rTRqc3pq7OLs9i53nnExdgl2aXS5a4rzTXSdYvrZTeMm6/bGrezbp/cnd2z3U+4/+lh7ZHuUesxPMdsDnfOoTkDnoaeLM8DnjIvuley149eMm8Db5Z3lfdTHyMfjs9hnyGGBSONcZTxytfWV+x72veDn7vfKr9Wf5R/kH+hf0+AWkBsQHnAk0DDQF5gXeBokFPQiqDWYExwaPCO4LtMXSabWcMcDXEJWRXSEUoOjQ4tD30aZhkmDmsJh8NDwneGP5prMlc4tykCRDAjdkY8jjSLXBL5yzzsvMh5FfOeRdlFrYzqiqZGL46ujX4f4xuzLeZhrHmsNLYtTjluQVxN3Id4//jieFnC7IRVCdcStRMFic1JuKS4pMNJY/MD5u+aP7jAaUHBgjsLzRYuW3hlkfaijEXnFisvZi0+mYxJjk+uTf7CimBVscZSmCmVKaNsP/Zu9guOD6eEM8L15BZzh1I9U4tTh3mevJ28Eb43v5T/UuAnKBe8TgtO25/2IT0i/Ui6PCM+oyETn5mceUaoJkwXdmTpZS3L6hVZiQpEsiXuS3YtGRWHig9LIMlCSXM2DWmGuqXm0g3S/hyvnIqcj0vjlp5cprpMuKx7ueXyzcuHcgNzf1qBXsFe0bbSYOXalf2rGKsOrIZWp6xuW2O0Jn/NYF5QXvVa4tr0tb+us11XvO7d+vj1Lfm6+Xn5AxuCNtQVKBWIC+5u9Ni4fxN6k2BTz2aHzXs2fyvkFF4tsi0qLfqyhb3l6g92P5T9IN+aurVnm/O2fdux24Xb7+zw3lFdrFqcWzywM3xnYwm9pLDk3a7Fu66UOpbu303cLd0tKwsra95jvGf7ni/l/PLbFb4VDZU6lZsrP+zl7O3b57Ovfr/u/qL9n38U/HjvQNCBxirTqtKD2IM5B58dijvU9ZPrTzWHtQ8XHf56RHhEVh1V3VHjUlNTq1O7rQ6uk9aNHF1w9MYx/2PN9db1Bxo0GoqOg+PS489/Tv75zonQE20nXU/WnzI5VXmaerqwEWpc3jjaxG+SNSc2954JOdPW4tFy+hebX46cNThbcU793LbzxPP55+UXci+MtYpaX17kXRxoW9z2sD2h/VbHvI6eztDOy5cCL7V3MbouXPa8fPaK+5UzV12vNl1zvtbY7dR9+lenX0/3OPc0Xne53nzD7UZL75ze833efRdv+t+8dIt569rtubd778TeuXd3wV3ZPc694fsZ918/yHkw/jDvEeZR4WOVx6VPdJ5U/WbxW4PMWXau37+/+2n004cD7IEXv0t+/zKY/4zyrHRIf6hm2H747EjgyI3n858PvhC9GH9Z8IfqH5WvzF+d+tPnz+7RhNHB1+LX8jdb3mq9PfLO8V3bWOTYk/eZ78c/FH7U+lj9yfVT1+f4z0PjS7/gvpR9tfja8i302yN5plwuYolZ31sBFDLg1FQA3hwBgJIIABXpiYnzJ3vo74Im+/7vBP4TT/bZ3+UMQD0yTbRCjDykH8mbbGEprQBE+AAQ4wNgBwfF+KckqQ72k7GU6gDAGcjlb7IAICDjS5BcPh4pl3+tRIq9BcD54cnefUJY5IumnprYL6ns+5aXB/5F/wD/2RG5pH0joAAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAZtpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8iPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+MTQ8L2V4aWY6UGl4ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+MTg8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KixRvjgAAABxpRE9UAAAAAgAAAAAAAAAJAAAAKAAAAAkAAAAJAAAAj4YPeVMAAABbSURBVDgRYvwPBAxkAMaRoLG1eyJK4FiaGTM42lkTDC7GvNIaFI3WFqYMYUF+hDX2Tp7x/+GjJ3CFCdHhDIb6OnA+LgZjz6Tp/x89fgqWt7E0YwgN9MWlFkUcAAAA//904fPUAAAAfklEQVRjzCut+c8ABLIyUgxFOekMTExMIC5BwAjSyMnBwVBbXsjAzc1FUANcAUjjw8dP/pMKGI6fOkuqHrB6RhAJt54EBtkaGTr7pvzftnPv/1+/f5PkZHCoglwICtm4qFAGLQ01ohzMWFBe9//fv39wxVUleQziYqJwPi4GAL2V52rYzHVFAAAAAElFTkSuQmCC"; + + imageSettings.localRemoteOrEmbeddedFileObject = png; + + ImageAdjusterRunnable imageAdjusterRunnable = new ImageAdjusterRunnable(imageSettings, exceptions); + + imageAdjusterRunnable.run(); + + + Assert.assertEquals(0, imageAdjusterRunnable.getExceptions().size()); + + ImageSettings settings = imageAdjusterRunnable.getSettings(); + Assert.assertEquals(300.0, settings.dpi, 0); + Assert.assertEquals(3048, settings.containerWidth); + Assert.assertEquals(3810, settings.containerHeight); + Assert.assertEquals(png, settings.localRemoteOrEmbeddedFileObject); + } + +} diff --git a/src/test/java/com/proxeus/office/libre/exe/LibreOfficeFormatTest.java b/src/test/java/com/proxeus/office/libre/exe/LibreOfficeFormatTest.java new file mode 100644 index 0000000..33a3d52 --- /dev/null +++ b/src/test/java/com/proxeus/office/libre/exe/LibreOfficeFormatTest.java @@ -0,0 +1,37 @@ +package com.proxeus.office.libre.exe; + +import org.junit.Test; + +import static com.proxeus.office.libre.exe.LibreOfficeFormat.*; +import static org.junit.Assert.*; + +public class LibreOfficeFormatTest { + + @Test(expected = Exception.class) + public void get_shouldThrowExceptionWithNull() throws Exception { + get(null); + } + + @Test(expected = Exception.class) + public void get_shouldThrowExceptionWithEmptyString() throws Exception { + get(""); + } + + @Test(expected = Exception.class) + public void get_shouldThrowExceptionWithNonExistingFormat() throws Exception { + get("ian"); + } + + @Test + public void get_shouldReturnCorrectFormats() throws Exception { + assertEquals(PDF, get("PDF")); + assertEquals(PDF, get("pdf")); + assertEquals(MS_DOCX, get("ms-docx")); + assertEquals(MS_DOCX, get("ms-DOCX")); + assertEquals(DOCX, get("oo-docx")); + assertEquals(MS_DOCX, get("docx")); + assertEquals(MS_DOC, get("ms-doc")); + assertEquals(MS_DOC, get("doc")); + assertEquals(ODT, get("odt")); + } +} \ No newline at end of file diff --git a/src/test/java/com/proxeus/office/libre/exe/LibreOfficeTest.java b/src/test/java/com/proxeus/office/libre/exe/LibreOfficeTest.java new file mode 100644 index 0000000..f1e12e2 --- /dev/null +++ b/src/test/java/com/proxeus/office/libre/exe/LibreOfficeTest.java @@ -0,0 +1,15 @@ +package com.proxeus.office.libre.exe; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class LibreOfficeTest { + + @Test + public void isNumber() { + assertTrue(LibreOffice.isNumber(new StringBuffer("5"))); + assertTrue(LibreOffice.isNumber(new StringBuffer("54545689458694589846689945868948684968496488649865948646"))); + assertFalse(LibreOffice.isNumber(new StringBuffer("abc"))); + } +} \ No newline at end of file diff --git a/src/test/java/com/proxeus/xml/XmlTemplateHandlerTest.java b/src/test/java/com/proxeus/xml/XmlTemplateHandlerTest.java deleted file mode 100644 index 5f4e1b7..0000000 --- a/src/test/java/com/proxeus/xml/XmlTemplateHandlerTest.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.proxeus.xml; - -import com.proxeus.document.TemplateCompiler; - -import org.junit.Assert; -import org.junit.Test; - -import java.util.List; - -public class XmlTemplateHandlerTest { - @Test - public void fixCodeStructures() throws Exception { - XmlTemplateHandler expected = getXmlTemplateFixer2("fixed_template_with_code.xml"); - XmlTemplateHandler mxf = getXmlTemplateFixer2("malformed_template_with_code.xml"); - String fixed_template_with_code = expected.toString(); - List<Element> imgEles = mxf.findElementsByName("imgele"); - imgEles.get(0).attr("name:var", "img123"); - mxf.fixCodeStructures(); - String fixed = mxf.toString(); - Assert.assertEquals(fixed_template_with_code, fixed); - } - - @Test - public void findElementsByNameFromRoot() throws Exception { - XmlTemplateHandler mxf = getXmlTemplateFixer(); - List<Element> spans = mxf.findElementsByName("span"); - Assert.assertEquals(4, spans.size()); - } - - @Test - public void findElementsByNameByChild() throws Exception { - XmlTemplateHandler mxf = getXmlTemplateFixer(); - List<Element> lis = mxf.findElementsByName("li:a"); - List<Element> innerLi = lis.get(3).findElementByName("li:a"); - Assert.assertEquals(1, innerLi.size()); - } - - @Test - public void attrWithValue() throws Exception { - XmlTemplateHandler mxf = getXmlTemplateFixer(); - List<Element> lis = mxf.findElementsByName("li:a"); - List<Element> innerLi = lis.get(3).findElementByName("li:a"); - Element target = innerLi.get(0); - target.attr("abc", "111"); - Assert.assertEquals("<li:a abc=\"111\">", target.start.toString()); - target.attr("hello", "123"); - Assert.assertEquals(true, target.start.toString().contains("hello=\"123\"")); - } - - @Test - public void attrWithValue2() throws Exception { - XmlTemplateHandler mxf = getXmlTemplateFixer(); - List<Element> lis = mxf.findElementsByName("li:a"); - List<Element> innerLi = lis.get(3).findElementByName("li:a"); - Element target = innerLi.get(0); - Assert.assertEquals("4.1", target.attr("abc")); - target.attr("hello", "123 \" ' "); - Assert.assertEquals("123 \" ' ", target.attr("hello")); - } - - @Test - public void attrWithValue3() throws Exception { - XmlTemplateHandler mxf = getXmlTemplateFixer(); - List<Element> lis = mxf.findElementsByName("draw:frame"); - List<Element> innerLi = lis.get(0).findElementByName("draw:image"); - Element target = innerLi.get(0); - lis.get(0).attr("draw:name", "newDrawName..."); - target.attr("loext:mime-type", "image/png"); - Assert.assertEquals("image/png", target.attr("loext:mime-type")); - } - - @Test - public void rootNodeContainingCode() throws Exception { - XmlTemplateHandler mxf = getXmlTemplateFixer(); - List<Element> lis = mxf.findElementsByName("draw:frame"); - List<Element> innerLi = lis.get(0).findElementByName("draw:image"); - Element target = innerLi.get(0); - lis.get(0).attr("draw:name", "newDrawName..."); - target.attr("loext:mime-type", "image/png"); - mxf.fixCodeStructures(); - Node rootNodeContainingCode = mxf.getRootNodeContainingCode(); - Assert.assertEquals("body", rootNodeContainingCode.name()); - } - - private XmlTemplateHandler getXmlTemplateFixer() throws Exception { - Config configTryToPlaceCodeMoreSuitable = new Config(); - configTryToPlaceCodeMoreSuitable.FixCodeByFindingTheNextCommonParent = true; - configTryToPlaceCodeMoreSuitable.Fix_XMLTags = false; - return new XmlTemplateHandler(configTryToPlaceCodeMoreSuitable, TemplateCompiler.class.getClassLoader().getResourceAsStream("parse_test.xml")); - } - - private XmlTemplateHandler getXmlTemplateFixer2(String filename) throws Exception { - Config configTryToPlaceCodeMoreSuitable = new Config(); - configTryToPlaceCodeMoreSuitable.FixCodeByFindingTheNextCommonParent = true; - configTryToPlaceCodeMoreSuitable.AddTryToWrapXMLTagWithCode("for", "table:table-row"); - configTryToPlaceCodeMoreSuitable.Fix_XMLTags = false; - return new XmlTemplateHandler(configTryToPlaceCodeMoreSuitable, TemplateCompiler.class.getClassLoader().getResourceAsStream(filename)); - } - -} diff --git a/src/test/java/com/proxeus/xml/processor/NoOpEventProcessorTest.java b/src/test/java/com/proxeus/xml/processor/NoOpEventProcessorTest.java new file mode 100644 index 0000000..157a78d --- /dev/null +++ b/src/test/java/com/proxeus/xml/processor/NoOpEventProcessorTest.java @@ -0,0 +1,56 @@ +package com.proxeus.xml.processor; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import javax.xml.stream.XMLEventFactory; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@RunWith(Parameterized.class) +public class NoOpEventProcessorTest { + + private List<String> test; + private XMLEventFactory eventFactory; + + public NoOpEventProcessorTest(List<String> test) { + this.test = test; + this.eventFactory = XMLEventFactory.newInstance(); + } + + @Parameterized.Parameters(name = "{index}: {0}") + public static Iterable<? extends Object> tests() { + return Arrays.asList( + Arrays.asList(), + Arrays.asList("a", "b", "c")); + } + + @Test + public void test() { + try { + XMLEventBuffer in = new XMLEventBuffer(); + XMLEventBuffer out = new XMLEventBuffer(); + + for (String s : test) { + in.add(eventFactory.createCharacters(s)); + } + + NoOpEventProcessor p = new NoOpEventProcessor(); + p.process(in, out); + + + List<String> result = new ArrayList<>(); + while (out.hasNext()) { + result.add(out.nextEvent().asCharacters().getData()); + } + Assert.assertArrayEquals(test.toArray(), result.toArray()); + } catch (Exception e) { + Assert.fail(); + } + + } + +} \ No newline at end of file diff --git a/src/test/java/com/proxeus/xml/processor/XMLEventProcessorChainTest.java b/src/test/java/com/proxeus/xml/processor/XMLEventProcessorChainTest.java new file mode 100644 index 0000000..654a96c --- /dev/null +++ b/src/test/java/com/proxeus/xml/processor/XMLEventProcessorChainTest.java @@ -0,0 +1,108 @@ +package com.proxeus.xml.processor; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import javax.xml.stream.XMLEventFactory; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@RunWith(Parameterized.class) +public class XMLEventProcessorChainTest { + + private List<String> test; + private XMLEventFactory eventFactory; + + public XMLEventProcessorChainTest(List<String> test) { + this.test = test; + this.eventFactory = XMLEventFactory.newInstance(); + } + + @Parameterized.Parameters(name = "{index}: {0}") + public static Iterable<? extends Object> tests() { + return Arrays.asList( + Arrays.asList(), + Arrays.asList("a", "b", "c")); + } + + @Test + public void test() { + try { + XMLEventBuffer in = new XMLEventBuffer(); + XMLEventBuffer out = new XMLEventBuffer(); + + for (String s : test) { + in.add(eventFactory.createCharacters(s)); + } + + XMLEventProcessorChain p = new XMLEventProcessorChain( + new NoOpEventProcessor(), + new NoOpEventProcessor() + ); + + p.process(in, out); + + List<String> result = new ArrayList<>(); + while (out.hasNext()) { + result.add(out.nextEvent().asCharacters().getData()); + } + Assert.assertArrayEquals(test.toArray(), result.toArray()); + } catch (Exception e) { + Assert.fail(); + } + + } + + @Test + public void testEmpty() { + try { + XMLEventBuffer in = new XMLEventBuffer(); + XMLEventBuffer out = new XMLEventBuffer(); + + for (String s : test) { + in.add(eventFactory.createCharacters(s)); + } + + XMLEventProcessorChain p = new XMLEventProcessorChain(); + + p.process(in, out); + + List<String> result = new ArrayList<>(); + while (out.hasNext()) { + result.add(out.nextEvent().asCharacters().getData()); + } + Assert.assertArrayEquals(test.toArray(), result.toArray()); + } catch (Exception e) { + Assert.fail(); + } + + } + + @Test + public void testHierarchy() { + try { + XMLEventBuffer in = new XMLEventBuffer(); + XMLEventBuffer out = new XMLEventBuffer(); + + for (String s : test) { + in.add(eventFactory.createCharacters(s)); + } + + XMLEventProcessorChain p = new XMLEventProcessorChain(new XMLEventProcessorChain()); + + p.process(in, out); + + List<String> result = new ArrayList<>(); + while (out.hasNext()) { + result.add(out.nextEvent().asCharacters().getData()); + } + Assert.assertArrayEquals(test.toArray(), result.toArray()); + } catch (Exception e) { + Assert.fail(); + } + + } +} diff --git a/src/test/java/com/proxeus/xml/template/CleanEmptyElementProcessorTest.java b/src/test/java/com/proxeus/xml/template/CleanEmptyElementProcessorTest.java new file mode 100644 index 0000000..08f7635 --- /dev/null +++ b/src/test/java/com/proxeus/xml/template/CleanEmptyElementProcessorTest.java @@ -0,0 +1,82 @@ +package com.proxeus.xml.template; + +import com.proxeus.xml.processor.XMLEventProcessor; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; +import java.io.*; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + + +@RunWith(Parameterized.class) +public class CleanEmptyElementProcessorTest { + + private static String TEXT = "urn:oasis:names:tc:opendocument:xmlns:text:1.0"; + private static QName TEXT_SPAN = new QName(TEXT, "span"); + private static QName TEXT_P = new QName(TEXT, "p"); + + private static List<QName> EMPTY_XML_ELEMENT_TO_REMOVE = Arrays.asList(TEXT_SPAN, TEXT_P); + + private String test; + + public CleanEmptyElementProcessorTest(String test) { + this.test = test; + } + + @Parameterized.Parameters(name = "{index}: {0}") + public static Iterable<? extends Object> tests() { + return Arrays.asList( + "template_with_code2_fixed.xml:template_with_code2_fixed.xml", + "content_fixed.xml:content_fixed_cleaned.xml", + "empty_element.xml:empty_element_cleaned.xml" + ); + } + + @Test + public void test() { + + String[] filenames = test.split(":"); + + XMLEventProcessor cleaner = new CleanEmptyElementProcessor(EMPTY_XML_ELEMENT_TO_REMOVE); + + InputStream input = getClass().getClassLoader().getResourceAsStream(filenames[0]); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + + // First, create a new XMLInputFactory + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + // Setup a new eventReader + + try { + XMLEventReader reader = inputFactory.createXMLEventReader(input); + XMLEventWriter writer = XMLOutputFactory.newInstance().createXMLEventWriter(output); + cleaner.process(reader, writer); + } catch (Exception e) { + e.printStackTrace(); + } + + try { + InputStream expected = getClass().getClassLoader().getResourceAsStream(filenames[1]); + Assert.assertEquals(convert(expected, Charset.defaultCharset()), output.toString()); + } catch (IOException e) { + + } + + } + + private String convert(InputStream inputStream, Charset charset) throws IOException { + try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, charset))) { + return br.lines().collect(Collectors.joining(System.lineSeparator())); + } + } + +} \ No newline at end of file diff --git a/src/test/java/com/proxeus/xml/template/DefaultTemplateHandlerTest.java b/src/test/java/com/proxeus/xml/template/DefaultTemplateHandlerTest.java new file mode 100644 index 0000000..0702267 --- /dev/null +++ b/src/test/java/com/proxeus/xml/template/DefaultTemplateHandlerTest.java @@ -0,0 +1,59 @@ +package com.proxeus.xml.template; + +import com.proxeus.xml.processor.XMLEventProcessor; +import com.proxeus.xml.template.jtwig.JTwigParser; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.io.*; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.stream.Collectors; + +@RunWith(Parameterized.class) +public class DefaultTemplateHandlerTest { + private String test; + + public DefaultTemplateHandlerTest(String test) { + this.test = test; + } + + @Parameterized.Parameters(name = "{index}: {0}") + public static Iterable<? extends Object> tests() { + return Arrays.asList( + "xml_tags_in_island", + "template_with_code2", + "if_statement", + "input1", + "xml_element_spanning_template_blocks", + "content"); + } + + @Test + public void test() { + + try { + XMLEventProcessor extractor = new TemplateExtractor(new JTwigParser()); + + InputStream input = getClass().getClassLoader().getResourceAsStream(test + ".xml"); + DefaultTemplateHandler handler = new DefaultTemplateHandler(extractor, new NoOpTemplateRenderer()); + handler.process(input); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + + handler.render(output, null); + + InputStream expected = JTwigParser.class.getClassLoader().getResourceAsStream(test + "_fixed.xml"); + Assert.assertEquals(convert(expected, Charset.defaultCharset()), output.toString()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private String convert(InputStream inputStream, Charset charset) throws IOException { + try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, charset))) { + return br.lines().collect(Collectors.joining(System.lineSeparator())); + } + } +} diff --git a/src/test/java/com/proxeus/xml/template/TemplateExtractorTest.java b/src/test/java/com/proxeus/xml/template/TemplateExtractorTest.java new file mode 100644 index 0000000..d9327db --- /dev/null +++ b/src/test/java/com/proxeus/xml/template/TemplateExtractorTest.java @@ -0,0 +1,79 @@ +package com.proxeus.xml.template; + +import com.proxeus.xml.processor.XMLEventProcessor; +import com.proxeus.xml.template.jtwig.JTwigParser; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; +import java.io.*; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.stream.Collectors; + +@RunWith(Parameterized.class) +public class TemplateExtractorTest { + + private String test; + + public TemplateExtractorTest(String test) { + this.test = test; + } + + @Parameters(name = "{index}: {0}") + public static Iterable<? extends Object> tests() { + return Arrays.asList( + "xml_tags_in_island", + "template_with_code2", + "if_statement", + "input1", + "xml_element_spanning_template_blocks", + "content", + "content_with_error"); + } + + @Test + public void test() throws Exception{ + XMLEventProcessor extractor = new TemplateExtractor(new JTwigParser()); + + InputStream input = getClass().getClassLoader().getResourceAsStream(test + ".xml"); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + + // First, create a new XMLInputFactory + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + // Setup a new eventReader + + try { + XMLEventReader reader = inputFactory.createXMLEventReader(input); + XMLEventWriter writer = XMLOutputFactory.newInstance().createXMLEventWriter(output); + extractor.process(reader, writer); + } catch (Exception e) { + e.printStackTrace(); + } + + String result = output.toString(); + + BufferedWriter writer = new BufferedWriter(new FileWriter("/tmp/content_with_error_fixed.xml")); + writer.write(result); + writer.close(); + + try { + InputStream expected = JTwigParser.class.getClassLoader().getResourceAsStream(test + "_fixed.xml"); + Assert.assertEquals(convert(expected, Charset.defaultCharset()), result); + } catch (IOException e) { + + } + } + + private String convert(InputStream inputStream, Charset charset) throws IOException { + try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, charset))) { + return br.lines().collect(Collectors.joining(System.lineSeparator())); + } + } +} diff --git a/src/test/java/com/proxeus/xml/template/TemplateVarProcessorTest.java b/src/test/java/com/proxeus/xml/template/TemplateVarProcessorTest.java new file mode 100644 index 0000000..5d698d8 --- /dev/null +++ b/src/test/java/com/proxeus/xml/template/TemplateVarProcessorTest.java @@ -0,0 +1,120 @@ +package com.proxeus.xml.template; + +import com.proxeus.xml.processor.XMLEventProcessor; +import com.proxeus.xml.processor.XMLEventProcessorChain; +import com.proxeus.xml.template.jtwig.JTwigParser; +import com.proxeus.xml.template.jtwig.JTwigVarParser; +import org.apache.commons.text.StringEscapeUtils; +import org.junit.Assert; +import org.junit.Test; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +public class TemplateVarProcessorTest { + + + @Test + public void process() { + + List<String> codes = new ArrayList<>(); + + codes.add("{{easy}} ".trim()); + codes.add("{% set easy=\"Proxeus makes document templating easier\" %} ".trim()); + codes.add("{{input.ImageFile1}} ".trim()); + codes.add("{{input.Var1*input.Var2}} ".trim()); + codes.add("{{input.Var1*input.Var2}} ".trim()); + codes.add("{{input.Var3/input.Var2}} ".trim()); + codes.add("{{input.Var3/input.Var2}} ".trim()); + codes.add("{{input.Var4}} ".trim()); + codes.add("{{(input.Var1>8)?\"Var is higher than 8\":\"Var is lower than 8\"}}".trim()); + codes.add("{{default(undefinedVariable,'World')}} ".trim()); + codes.add("{%if (condition)%} ".trim()); + codes.add("{%elseif (condition2)%} ".trim()); + codes.add("{{loop.index0}} ".trim()); + codes.add("{{loop.index}} ".trim()); + codes.add("{{item}} ".trim()); + codes.add("{% for item in [1,2,3] %} ".trim()); + codes.add("{{total*1000|number_format(2, \".\", \"'\")}} ".trim()); + codes.add("{{loop.index0}} ".trim()); + codes.add("{{loop.index}} ".trim()); + codes.add("{{item}} ".trim()); + codes.add("{% for item in [1,2,3] %} ".trim()); + codes.add("{{total*1000|number_format(2, \".\", \"'\")}} ".trim()); + codes.add("{{ (iB.printed)?\"again \":\"\" }} ".trim()); + codes.add("{{ (iB.printed)?myVarInsideInlineCond:SecondVarInsideInlineCond }} ".trim()); + codes.add("{{ iB.Name }} ".trim()); + codes.add("{% block inlineBlock %} ".trim()); + codes.add("{{iB.Name}} ".trim()); + codes.add("{% block paragraphBlock %} ".trim()); + codes.add("{{firstname}} ".trim()); + codes.add("{{lastname}} ".trim()); + codes.add("{{age}} ".trim()); + codes.add("{{firstname}} ".trim()); + codes.add("{%if (age<25) %} ".trim()); + codes.add("{%elseif (age>25 and age<32) %} ".trim()); + codes.add("{%elseif (age>25 and age<32) %} ".trim()); + codes.add("{% macro person (firstname, lastname, age) %} ".trim()); + codes.add("{% macro person (firstname, lastname, age) %} ".trim()); + codes.add("{% macro person (firstname, lastname, age) %} ".trim()); + codes.add("{% set input={Var1:10,Var2:25,Var3:1000,Var4:\"Text Value\"} %} ".trim()); + codes.add("{% set total=0 %} ".trim()); + codes.add("{% set total=item+total %} ".trim()); + codes.add("{% set total=item+total %} ".trim()); + codes.add("{% set total=item+total %} ".trim()); + codes.add("{% set total=0 %} ".trim()); + codes.add("{% set total=item+total %} ".trim()); + codes.add("{% set total=item+total %} ".trim()); + codes.add("{% set total=item+total %} ".trim()); + codes.add("{% set iB={\"printed\":false,\"Name\":\"Steve\"} %} ".trim()); + codes.add("{% set iB={\"Name\":\"John\"} %} ".trim()); + codes.add("{{input.ImageFile1}} ".trim()); + codes.add("{{loop.index0}} ".trim()); + codes.add("{{loop.index}} ".trim()); + codes.add("{{item}} ".trim()); + codes.add("{% for item in [1,2,3] %} ".trim()); + codes.add("{{total*1000|number_format(2, \".\", \"'\")}} ".trim()); + codes.add("{% set total=0 %} ".trim()); + codes.add("{% set total=item+total %} ".trim()); + codes.add("{% set total=item+total %} ".trim()); + codes.add("{% set total=item+total %} ".trim()); + + StringBuffer sb = new StringBuffer(); + sb.append("<root>\n"); + for (String code : codes) { + + sb.append("<span>\n"); + sb.append(StringEscapeUtils.escapeXml11(code)); + sb.append("\n</span>\n"); + } + sb.append("\n</root>"); + + + TemplateVarParser parser = new JTwigVarParser(null); + XMLEventProcessor processor = new XMLEventProcessorChain( + new TemplateExtractor(new JTwigParser()), + // TemplateVarProcessor assumes that each code and content island are in their own characters event + new TemplateVarProcessor(parser) + ); + + ByteArrayOutputStream output = new ByteArrayOutputStream(); + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + + try { + XMLEventReader reader = inputFactory.createXMLEventReader(new ByteArrayInputStream(sb.toString().getBytes(Charset.defaultCharset()))); + XMLEventWriter writer = XMLOutputFactory.newInstance().createXMLEventWriter(output); + processor.process(reader, writer); + } catch (Exception e) { + e.printStackTrace(); + } + + Assert.assertEquals("[age, condition, condition2, easy, firstname, iB, iB.Name, iB.printed, inlineBlock, input, input.ImageFile1, input.Var1, input.Var2, input.Var3, input.Var4, item, lastname, loop.index, loop.index0, myVarInsideInlineCond, paragraphBlock, SecondVarInsideInlineCond, total, undefinedVariable]", parser.getVars().toString()); + } +} \ No newline at end of file diff --git a/src/test/java/com/proxeus/xml/template/jtwig/JTwigParserTest.java b/src/test/java/com/proxeus/xml/template/jtwig/JTwigParserTest.java new file mode 100644 index 0000000..3c85861 --- /dev/null +++ b/src/test/java/com/proxeus/xml/template/jtwig/JTwigParserTest.java @@ -0,0 +1,26 @@ +package com.proxeus.xml.template.jtwig; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; + +public class JTwigParserTest { + + @Test + public void extractCommandTest() { + // [input, expected] + String[][] tests = new String[][]{ + {"1", "", ""}, + {"2", "{% if", "if"}, + {"3", "{% if ", "if"}, + {"4", "{%if ", "if"}, + {"5", "{%if %} ", "if"}, + {"6", "{%if%} ", "if"}, + + }; + + Arrays.asList(tests).forEach(test -> + Assert.assertEquals(test[0], test[2], JTwigParser.extractCommand(test[1]) )); + } +} diff --git a/src/test/java/com/proxeus/xml/VarParserTest.java b/src/test/java/com/proxeus/xml/template/jtwig/JTwigVarParserTest.java similarity index 96% rename from src/test/java/com/proxeus/xml/VarParserTest.java rename to src/test/java/com/proxeus/xml/template/jtwig/JTwigVarParserTest.java index d0686ef..7814245 100644 --- a/src/test/java/com/proxeus/xml/VarParserTest.java +++ b/src/test/java/com/proxeus/xml/template/jtwig/JTwigVarParserTest.java @@ -1,4 +1,4 @@ -package com.proxeus.xml; +package com.proxeus.xml.template.jtwig; import org.junit.Assert; import org.junit.Test; @@ -6,10 +6,10 @@ import java.util.ArrayList; import java.util.List; -public class VarParserTest { +public class JTwigVarParserTest { @Test public void parser() throws Exception { - VarParser parser = new VarParser(null); + JTwigVarParser parser = new JTwigVarParser(null); List<String> codes = new ArrayList<>(); codes.add("{{easy}} ".trim()); codes.add("{% set easy=\"Proxeus makes document templating easier\" %} ".trim()); @@ -70,9 +70,9 @@ public void parser() throws Exception { codes.add("{% set total=item+total %} ".trim()); codes.add("{% set total=item+total %} ".trim()); codes.add("{% set total=item+total %} ".trim()); - for(String code : codes){ - parser.Parse(code); + for (String code : codes) { + parser.parse(code); } - Assert.assertEquals("[age, condition, condition2, easy, firstname, iB, iB.Name, iB.printed, inlineBlock, input, input.ImageFile1, input.Var1, input.Var2, input.Var3, input.Var4, item, lastname, loop.index, loop.index0, myVarInsideInlineCond, paragraphBlock, SecondVarInsideInlineCond, total, undefinedVariable]",parser.Vars().toString()); + Assert.assertEquals("[age, condition, condition2, easy, firstname, iB, iB.Name, iB.printed, inlineBlock, input, input.ImageFile1, input.Var1, input.Var2, input.Var3, input.Var4, item, lastname, loop.index, loop.index0, myVarInsideInlineCond, paragraphBlock, SecondVarInsideInlineCond, total, undefinedVariable]", parser.getVars().toString()); } } diff --git a/src/test/resources/.~lock.simple.odt# b/src/test/resources/.~lock.simple.odt# new file mode 100644 index 0000000..22eedd4 --- /dev/null +++ b/src/test/resources/.~lock.simple.odt# @@ -0,0 +1 @@ +,emeka,Emekas-MacBook-Pro.local,03.03.2020 20:24,file:///private/var/folders/qm/dp53yk716rb04pj7t143_r500000gn/T/loui_e583267a-9187-4c86-9330-b0e3dd111a6e; \ No newline at end of file diff --git a/src/test/resources/content.xml b/src/test/resources/content.xml new file mode 100644 index 0000000..ac0a4ad --- /dev/null +++ b/src/test/resources/content.xml @@ -0,0 +1,1009 @@ +<?xml version="1.0" encoding="UTF-8"?> +<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" + xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" + xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" + xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" + xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" + xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" + xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" + xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" + xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" + xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" + xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" + xmlns:math="http://www.w3.org/1998/Math/MathML" + xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" + xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" + xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" + xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" + xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:rpt="http://openoffice.org/2005/report" + xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" + xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" + xmlns:officeooo="http://openoffice.org/2009/office" + xmlns:tableooo="http://openoffice.org/2009/table" + xmlns:drawooo="http://openoffice.org/2010/draw" + xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" + xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" + xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" + xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" + xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2"> + <office:scripts/> + <office:font-face-decls> + <style:font-face style:name="Symbol" svg:font-family="Symbol" style:font-family-generic="roman" + style:font-pitch="variable" style:font-charset="x-symbol"/> + <style:font-face style:name="Wingdings" svg:font-family="Wingdings" style:font-family-generic="system" + style:font-pitch="variable" style:font-charset="x-symbol"/> + <style:font-face style:name="Univers LT 45 Light" svg:font-family="'Univers LT 45 Light'" + style:font-family-generic="roman"/> + <style:font-face style:name="The Sans Semi Bold" svg:font-family="'The Sans Semi Bold'" + style:font-family-generic="swiss"/> + <style:font-face style:name="Courier New" svg:font-family="'Courier New'" + style:font-family-generic="modern" style:font-pitch="fixed"/> + <style:font-face style:name="LinePrinter" svg:font-family="LinePrinter" style:font-family-generic="modern" + style:font-pitch="fixed"/> + <style:font-face style:name="Arial1" svg:font-family="Arial" style:font-family-generic="roman" + style:font-pitch="variable"/> + <style:font-face style:name="Arial Unicode MS" svg:font-family="'Arial Unicode MS'" + style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" + style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Times New Roman" svg:font-family="'Times New Roman'" + style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Arial" svg:font-family="Arial" style:font-family-generic="swiss" + style:font-pitch="variable"/> + <style:font-face style:name="Calibri" svg:font-family="Calibri" style:font-family-generic="swiss" + style:font-pitch="variable"/> + <style:font-face style:name="Calibri1" svg:font-family="Calibri" style:font-adornments="Regular" + style:font-family-generic="swiss" style:font-pitch="variable"/> + <style:font-face style:name="Helv" svg:font-family="Helv" style:font-family-generic="swiss" + style:font-pitch="variable"/> + <style:font-face style:name="Liberation Sans" svg:font-family="'Liberation Sans'" + style:font-family-generic="swiss" style:font-pitch="variable"/> + <style:font-face style:name="Tahoma" svg:font-family="Tahoma" style:font-family-generic="swiss" + style:font-pitch="variable"/> + <style:font-face style:name="MS Gothic" svg:font-family="'MS Gothic'" + style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="Tahoma1" svg:font-family="Tahoma" style:font-family-generic="system" + style:font-pitch="variable"/> + <style:font-face style:name="Univers 45 Light" svg:font-family="'Univers 45 Light'" + style:font-family-generic="system" style:font-pitch="variable"/> + </office:font-face-decls> + <office:automatic-styles> + <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Text_20_body" + style:master-page-name=""> + <style:paragraph-properties style:line-height-at-least="0.1528in" fo:hyphenation-ladder-count="no-limit" + style:page-number="auto" fo:padding="0.0193in" fo:border-left="none" + fo:border-right="none" fo:border-top="0.06pt solid #000000" + fo:border-bottom="none" style:join-border="false"> + <style:tab-stops> + <style:tab-stop style:position="5.9028in" style:type="right"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" officeooo:rsid="004b6859" loext:padding-left="0in" + loext:padding-right="0in" loext:padding-top="0.0193in" loext:padding-bottom="0in" + loext:border="none" fo:hyphenate="true" fo:hyphenation-remain-char-count="2" + fo:hyphenation-push-char-count="2"/> + </style:style> + <style:style style:name="P2" style:family="paragraph" style:parent-style-name="Footer"> + <style:paragraph-properties fo:padding-left="0in" fo:padding-right="0in" fo:padding-top="0.0138in" + fo:padding-bottom="0in" fo:border-left="none" fo:border-right="none" + fo:border-top="0.51pt solid #000000" fo:border-bottom="none" + style:shadow="none"> + <style:tab-stops> + <style:tab-stop style:position="5.8083in" style:type="center"/> + <style:tab-stop style:position="5.9063in" style:type="right"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="001fc62c"/> + </style:style> + <style:style style:name="P3" style:family="paragraph" style:parent-style-name="Footer"> + <style:paragraph-properties fo:padding-left="0in" fo:padding-right="0in" fo:padding-top="0.0138in" + fo:padding-bottom="0in" fo:border-left="none" fo:border-right="none" + fo:border-top="0.51pt solid #000000" fo:border-bottom="none" + style:shadow="none"> + <style:tab-stops> + <style:tab-stop style:position="5.8083in" style:type="center"/> + <style:tab-stop style:position="5.9063in" style:type="right"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0022fa95"/> + </style:style> + <style:style style:name="P4" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties style:line-height-at-least="0.1665in" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0in"/> + <style:tab-stop style:position="0.25in"/> + <style:tab-stop style:position="3.5425in"/> + <style:tab-stop style:position="3.9335in"/> + <style:tab-stop style:position="4.4252in"/> + <style:tab-stop style:position="4.9165in"/> + <style:tab-stop style:position="5.4083in"/> + <style:tab-stop style:position="5.9in"/> + <style:tab-stop style:position="6.3917in"/> + <style:tab-stop style:position="6.5in"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + officeooo:paragraph-rsid="0032fef0" style:font-size-asian="11pt" + style:language-asian="en" style:country-asian="US" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P5" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties style:line-height-at-least="0.1665in" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0in"/> + <style:tab-stop style:position="0.25in"/> + <style:tab-stop style:position="3.5425in"/> + <style:tab-stop style:position="3.9335in"/> + <style:tab-stop style:position="4.4252in"/> + <style:tab-stop style:position="4.9165in"/> + <style:tab-stop style:position="5.4083in"/> + <style:tab-stop style:position="5.9in"/> + <style:tab-stop style:position="6.3917in"/> + <style:tab-stop style:position="6.5in"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:font-size="16pt" fo:language="de" fo:country="DE" + officeooo:rsid="00346b24" officeooo:paragraph-rsid="00346b24" + style:font-size-asian="10pt" style:language-asian="en" style:country-asian="US" + style:font-size-complex="10pt"/> + </style:style> + <style:style style:name="P6" style:family="paragraph" style:parent-style-name="Standard1" + style:list-style-name="WWNum6"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"/> + <style:tab-stop style:position="0.3335in"/> + <style:tab-stop style:position="3.5425in"/> + <style:tab-stop style:position="3.9335in"/> + <style:tab-stop style:position="4.4252in"/> + <style:tab-stop style:position="4.9165in"/> + <style:tab-stop style:position="5.4083in"/> + <style:tab-stop style:position="5.9in"/> + <style:tab-stop style:position="6.3917in"/> + <style:tab-stop style:position="6.5in"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + fo:font-weight="bold" officeooo:paragraph-rsid="0032fef0" + style:font-size-asian="11pt" style:font-weight-asian="bold" + style:font-size-complex="11pt" style:font-weight-complex="bold"/> + </style:style> + <style:style style:name="P7" style:family="paragraph" style:parent-style-name="Standard1" + style:list-style-name="WWNum6"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"/> + <style:tab-stop style:position="0.3335in"/> + <style:tab-stop style:position="3.5425in"/> + <style:tab-stop style:position="3.9335in"/> + <style:tab-stop style:position="4.4252in"/> + <style:tab-stop style:position="4.9165in"/> + <style:tab-stop style:position="5.4083in"/> + <style:tab-stop style:position="5.9in"/> + <style:tab-stop style:position="6.3917in"/> + <style:tab-stop style:position="6.5in"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + officeooo:paragraph-rsid="0032fef0" style:font-size-asian="11pt" + style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P8" style:family="paragraph" style:parent-style-name="Standard1"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"/> + <style:tab-stop style:position="0.3335in"/> + <style:tab-stop style:position="3.5425in"/> + <style:tab-stop style:position="3.9335in"/> + <style:tab-stop style:position="4.4252in"/> + <style:tab-stop style:position="4.9165in"/> + <style:tab-stop style:position="5.4083in"/> + <style:tab-stop style:position="5.9in"/> + <style:tab-stop style:position="6.3917in"/> + <style:tab-stop style:position="6.5in"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + officeooo:paragraph-rsid="0032fef0" style:font-size-asian="11pt" + style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P9" style:family="paragraph" style:parent-style-name="Standard1" + style:list-style-name="WWNum6"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"/> + <style:tab-stop style:position="0.3335in"/> + <style:tab-stop style:position="3.5425in"/> + <style:tab-stop style:position="3.9335in"/> + <style:tab-stop style:position="4.4252in"/> + <style:tab-stop style:position="4.9165in"/> + <style:tab-stop style:position="5.4083in"/> + <style:tab-stop style:position="5.9in"/> + <style:tab-stop style:position="6.3917in"/> + <style:tab-stop style:position="6.5in"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"/> + </style:style> + <style:style style:name="P10" style:family="paragraph" style:parent-style-name="Standard1" + style:list-style-name="WWNum6"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"/> + <style:tab-stop style:position="0.3335in"/> + <style:tab-stop style:position="3.5425in"/> + <style:tab-stop style:position="3.9335in"/> + <style:tab-stop style:position="4.4252in"/> + <style:tab-stop style:position="4.9165in"/> + <style:tab-stop style:position="5.4083in"/> + <style:tab-stop style:position="5.9in"/> + <style:tab-stop style:position="6.3917in"/> + <style:tab-stop style:position="6.5in"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="00560a1d"/> + </style:style> + <style:style style:name="P11" style:family="paragraph" style:parent-style-name="Standard1" + style:list-style-name="WWNum6"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"/> + <style:tab-stop style:position="0.3335in"/> + <style:tab-stop style:position="3.5425in"/> + <style:tab-stop style:position="3.9335in"/> + <style:tab-stop style:position="4.4252in"/> + <style:tab-stop style:position="4.9165in"/> + <style:tab-stop style:position="5.4083in"/> + <style:tab-stop style:position="5.9in"/> + <style:tab-stop style:position="6.3917in"/> + <style:tab-stop style:position="6.5in"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="004cc6b6"/> + </style:style> + <style:style style:name="P12" style:family="paragraph" style:parent-style-name="Standard1" + style:list-style-name="WWNum6"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"/> + <style:tab-stop style:position="0.3335in"/> + <style:tab-stop style:position="3.5425in"/> + <style:tab-stop style:position="3.9335in"/> + <style:tab-stop style:position="4.4252in"/> + <style:tab-stop style:position="4.9165in"/> + <style:tab-stop style:position="5.4083in"/> + <style:tab-stop style:position="5.9in"/> + <style:tab-stop style:position="6.3917in"/> + <style:tab-stop style:position="6.5in"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="00465c76"/> + </style:style> + <style:style style:name="P13" style:family="paragraph" style:parent-style-name="Standard1"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"/> + <style:tab-stop style:position="0.3335in"/> + <style:tab-stop style:position="3.5425in"/> + <style:tab-stop style:position="3.9335in"/> + <style:tab-stop style:position="4.4252in"/> + <style:tab-stop style:position="4.9165in"/> + <style:tab-stop style:position="5.4083in"/> + <style:tab-stop style:position="5.9in"/> + <style:tab-stop style:position="6.3917in"/> + <style:tab-stop style:position="6.5in"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="00560a1d"/> + </style:style> + <style:style style:name="P14" style:family="paragraph" style:parent-style-name="Standard1" + style:list-style-name="WWNum6"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"/> + </style:style> + <style:style style:name="P15" style:family="paragraph" style:parent-style-name="List_20_Paragraph" + style:list-style-name="WWNum6"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" officeooo:paragraph-rsid="0032fef0" + style:font-size-asian="11pt" style:font-name-complex="Calibri" + style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P16" style:family="paragraph" style:parent-style-name="Body_20_Text" + style:list-style-name="WWNum6"> + <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" loext:contextual-spacing="false" + fo:line-height="100%"/> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:font-weight="bold" + officeooo:paragraph-rsid="0032fef0" style:font-size-asian="11pt" + style:font-weight-asian="bold" style:font-name-complex="Arial" + style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P17" style:family="paragraph" style:parent-style-name="Body_20_Text"> + <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" loext:contextual-spacing="false" + fo:line-height="100%"/> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:font-weight="bold" + officeooo:paragraph-rsid="0032fef0" style:font-size-asian="11pt" + style:font-weight-asian="bold" style:font-name-complex="Arial" + style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P18" style:family="paragraph" style:parent-style-name="Body_20_Text"> + <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" loext:contextual-spacing="false" + fo:line-height="100%"/> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:font-weight="bold" + officeooo:paragraph-rsid="0032fef0" style:font-size-asian="11pt" + style:font-weight-asian="bold" style:font-name-complex="Arial" + style:font-size-complex="11pt" style:font-weight-complex="bold"/> + </style:style> + <style:style style:name="P19" style:family="paragraph" style:parent-style-name="Body_20_Text" + style:list-style-name="WWNum6"> + <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" loext:contextual-spacing="false" + fo:line-height="100%"/> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:font-weight="bold" + officeooo:paragraph-rsid="0032fef0" style:font-size-asian="11pt" + style:font-weight-asian="bold" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P20" style:family="paragraph" style:parent-style-name="Body_20_Text"> + <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" loext:contextual-spacing="false" + fo:line-height="100%"/> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:font-weight="bold" + officeooo:paragraph-rsid="0032fef0" style:font-size-asian="11pt" + style:font-weight-asian="bold" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P21" style:family="paragraph" style:parent-style-name="Body_20_Text" + style:list-style-name="WWNum6"> + <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" loext:contextual-spacing="false" + fo:line-height="100%"/> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" officeooo:paragraph-rsid="0032fef0" + style:font-size-asian="11pt" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P22" style:family="paragraph" style:parent-style-name="Body_20_Text"> + <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" loext:contextual-spacing="false" + fo:line-height="100%"/> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" officeooo:paragraph-rsid="0032fef0" + style:font-size-asian="11pt" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P23" style:family="paragraph" style:parent-style-name="Body_20_Text" + style:list-style-name="WWNum6"> + <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" loext:contextual-spacing="false" + fo:line-height="100%"/> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" officeooo:paragraph-rsid="0032fef0" + style:font-size-asian="11pt" style:font-name-complex="Arial" + style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P24" style:family="paragraph" style:parent-style-name="Body_20_Text"> + <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" loext:contextual-spacing="false" + fo:line-height="100%"/> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" officeooo:paragraph-rsid="0032fef0" + style:font-size-asian="11pt" style:font-name-complex="Arial" + style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P25" style:family="paragraph" style:parent-style-name="Body_20_Text" + style:list-style-name="WWNum6"> + <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" loext:contextual-spacing="false" + fo:line-height="100%"/> + <style:text-properties officeooo:paragraph-rsid="0032fef0"/> + </style:style> + <style:style style:name="P26" style:family="paragraph" style:parent-style-name="Body_20_Text"> + <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0in" loext:contextual-spacing="false" + fo:line-height="100%"/> + <style:text-properties officeooo:paragraph-rsid="0032fef0"/> + </style:style> + <style:style style:name="P27" style:family="paragraph" style:parent-style-name="Body_20_Text" + style:list-style-name="L1"> + <style:paragraph-properties fo:margin-left="0.2236in" fo:margin-right="0in" fo:margin-top="0in" + fo:margin-bottom="0in" loext:contextual-spacing="false" fo:line-height="100%" + fo:text-indent="-0.2138in" style:auto-text-indent="false"> + <style:tab-stops/> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"/> + </style:style> + <style:style style:name="P28" style:family="paragraph" style:parent-style-name="Body_20_Text" + style:list-style-name="L1"> + <style:paragraph-properties fo:margin-left="0.2236in" fo:margin-right="0in" fo:margin-top="0in" + fo:margin-bottom="0in" loext:contextual-spacing="false" fo:line-height="100%" + fo:text-indent="-0.2138in" style:auto-text-indent="false"> + <style:tab-stops/> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" officeooo:paragraph-rsid="0032fef0" + style:font-size-asian="11pt" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P29" style:family="paragraph" style:parent-style-name="Body_20_Text" + style:list-style-name="L1"> + <style:paragraph-properties fo:margin-left="0.2236in" fo:margin-right="0in" fo:margin-top="0in" + fo:margin-bottom="0in" loext:contextual-spacing="false" fo:line-height="100%" + fo:text-indent="-0.2138in" style:auto-text-indent="false"> + <style:tab-stops/> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" officeooo:paragraph-rsid="0032fef0" + fo:background-color="#ffff00" style:font-size-asian="11pt" + style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P30" style:family="paragraph" style:parent-style-name="Body_20_Text"> + <style:paragraph-properties fo:margin-left="0in" fo:margin-right="0in" fo:margin-top="0.1929in" + fo:margin-bottom="0in" loext:contextual-spacing="false" fo:text-indent="0in" + style:auto-text-indent="false"/> + </style:style> + <style:style style:name="P31" style:family="paragraph" style:parent-style-name="Normal"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" officeooo:paragraph-rsid="0032fef0" + style:font-size-asian="11pt" style:font-name-complex="Calibri" + style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P32" style:family="paragraph" style:parent-style-name="Normal"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" officeooo:paragraph-rsid="0032fef0" + style:font-size-asian="11pt" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P33" style:family="paragraph" style:parent-style-name="Normal"> + <style:paragraph-properties> + <style:tab-stops> + <style:tab-stop style:position="2.9535in"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="00465c76"/> + </style:style> + <style:style style:name="P34" style:family="paragraph" style:parent-style-name="Normal"> + <style:paragraph-properties> + <style:tab-stops> + <style:tab-stop style:position="2.9535in"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="004cc6b6"/> + </style:style> + <style:style style:name="P35" style:family="paragraph" style:parent-style-name="Standard" + style:list-style-name="WWNum6"> + <style:paragraph-properties style:line-height-at-least="0.1665in" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0in"/> + <style:tab-stop style:position="0.25in"/> + <style:tab-stop style:position="3.5425in"/> + <style:tab-stop style:position="3.9335in"/> + <style:tab-stop style:position="4.4252in"/> + <style:tab-stop style:position="4.9165in"/> + <style:tab-stop style:position="5.4083in"/> + <style:tab-stop style:position="5.9in"/> + <style:tab-stop style:position="6.3917in"/> + <style:tab-stop style:position="6.5in"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"/> + </style:style> + <style:style style:name="P36" style:family="paragraph" style:parent-style-name="Standard" + style:list-style-name="WWNum6"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"/> + <style:tab-stop style:position="0.3335in"/> + <style:tab-stop style:position="3.5425in"/> + <style:tab-stop style:position="3.9335in"/> + <style:tab-stop style:position="4.4252in"/> + <style:tab-stop style:position="4.9165in"/> + <style:tab-stop style:position="5.4083in"/> + <style:tab-stop style:position="5.9in"/> + <style:tab-stop style:position="6.3917in"/> + <style:tab-stop style:position="6.5in"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"/> + </style:style> + <style:style style:name="P37" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties style:line-height-at-least="0.1665in" fo:text-align="justify" + style:justify-single-word="false"> + <style:tab-stops> + <style:tab-stop style:position="0in"/> + <style:tab-stop style:position="0.3335in"/> + <style:tab-stop style:position="3.5425in"/> + <style:tab-stop style:position="3.9335in"/> + <style:tab-stop style:position="4.4252in"/> + <style:tab-stop style:position="4.9165in"/> + <style:tab-stop style:position="5.4083in"/> + <style:tab-stop style:position="5.9in"/> + <style:tab-stop style:position="6.3917in"/> + <style:tab-stop style:position="6.5in"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"/> + </style:style> + <style:style style:name="P38" style:family="paragraph" style:parent-style-name="Standard" + style:list-style-name="WWNum6"> + <style:paragraph-properties style:line-height-at-least="0.1665in" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0in"/> + <style:tab-stop style:position="0.25in"/> + <style:tab-stop style:position="3.5425in"/> + <style:tab-stop style:position="3.9335in"/> + <style:tab-stop style:position="4.4252in"/> + <style:tab-stop style:position="4.9165in"/> + <style:tab-stop style:position="5.4083in"/> + <style:tab-stop style:position="5.9in"/> + <style:tab-stop style:position="6.3917in"/> + <style:tab-stop style:position="6.5in"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + officeooo:paragraph-rsid="0032fef0" style:font-size-asian="11pt" + style:language-asian="en" style:country-asian="US" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P39" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties style:line-height-at-least="0.1665in" fo:text-align="justify" + style:justify-single-word="false" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0in"/> + <style:tab-stop style:position="0.3335in"/> + <style:tab-stop style:position="3.5425in"/> + <style:tab-stop style:position="3.9335in"/> + <style:tab-stop style:position="4.4252in"/> + <style:tab-stop style:position="4.9165in"/> + <style:tab-stop style:position="5.4083in"/> + <style:tab-stop style:position="5.9in"/> + <style:tab-stop style:position="6.3917in"/> + <style:tab-stop style:position="6.5in"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + officeooo:paragraph-rsid="0032fef0" style:font-size-asian="11pt" + style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P40" style:family="paragraph" style:parent-style-name="Text_20_body"> + <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0.1181in" loext:contextual-spacing="false" + style:line-height-at-least="0.139in"/> + <style:text-properties officeooo:paragraph-rsid="0032fef0"/> + </style:style> + <style:style style:name="P41" style:family="paragraph" style:parent-style-name="Text_20_body"> + <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0.1181in" loext:contextual-spacing="false" + style:line-height-at-least="0.139in"/> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" officeooo:paragraph-rsid="0032fef0" + style:font-size-asian="11pt" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="T1" style:family="text"> + <style:text-properties fo:font-size="9pt"/> + </style:style> + <style:style style:name="T2" style:family="text"> + <style:text-properties fo:font-size="9pt" officeooo:rsid="003c7b76"/> + </style:style> + <style:style style:name="T3" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="9pt" style:font-size-asian="9pt" + style:font-name-complex="Arial"/> + </style:style> + <style:style style:name="T4" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="9pt" style:font-size-asian="9pt" + style:font-name-complex="Arial" style:font-size-complex="9pt"/> + </style:style> + <style:style style:name="T5" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="9pt" officeooo:rsid="002dfa47" + style:font-size-asian="9pt" style:font-name-complex="Arial" + style:font-size-complex="9pt"/> + </style:style> + <style:style style:name="T6" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="9pt" officeooo:rsid="002dfa47" + style:font-size-asian="9pt" style:font-name-complex="Arial"/> + </style:style> + <style:style style:name="T7" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + style:font-size-asian="11pt" style:language-asian="en" style:country-asian="US" + style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="T8" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + style:font-size-asian="11pt" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="T9" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + style:font-size-asian="11pt" style:font-size-complex="11pt" + style:font-weight-complex="bold"/> + </style:style> + <style:style style:name="T10" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + officeooo:rsid="00580dab" style:font-size-asian="11pt" + style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="T11" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + fo:font-weight="normal" fo:background-color="#ffffff" loext:char-shading-value="0" + style:font-size-asian="11pt" style:font-weight-asian="normal" + style:font-size-complex="11pt" style:font-weight-complex="normal"/> + </style:style> + <style:style style:name="T12" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + fo:font-weight="bold" style:font-size-asian="11pt" style:font-weight-asian="bold" + style:font-size-complex="11pt" style:font-weight-complex="bold"/> + </style:style> + <style:style style:name="T13" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + fo:background-color="#ffffff" loext:char-shading-value="0" + style:font-size-asian="11pt" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="T14" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="en" fo:country="US" + style:font-size-asian="11pt" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="T15" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="en" fo:country="US" + fo:font-weight="bold" style:font-size-asian="11pt" style:font-weight-asian="bold" + style:font-name-complex="Arial" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="T16" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="en" fo:country="US" + fo:font-weight="bold" style:font-size-asian="11pt" style:font-weight-asian="bold" + style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="T17" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="en" fo:country="US" + fo:background-color="#ffffff" loext:char-shading-value="0" + style:font-size-asian="11pt" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="T18" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="en" fo:country="US" + fo:background-color="#ffffff" loext:char-shading-value="0" + style:font-size-asian="11pt" style:language-asian="zxx" style:country-asian="none" + style:font-size-complex="11pt" style:language-complex="zxx" + style:country-complex="none"/> + </style:style> + <style:style style:name="T19" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="en" fo:country="US" + fo:font-weight="normal" fo:background-color="#ffffff" loext:char-shading-value="0" + style:font-size-asian="11pt" style:language-asian="zxx" style:country-asian="none" + style:font-weight-asian="normal" style:font-size-complex="11pt" + style:language-complex="zxx" style:country-complex="none" + style:font-weight-complex="normal"/> + </style:style> + <style:style style:name="T20" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:font-weight="bold" + style:font-size-asian="11pt" style:font-weight-asian="bold" + style:font-name-complex="Arial" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="T21" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:font-weight="bold" + style:font-size-asian="11pt" style:font-weight-asian="bold" + style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="T22" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" style:font-size-asian="11pt" + style:font-name-complex="Arial" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="T23" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" style:font-size-asian="11pt" + style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="T24" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="zxx" fo:country="none" + fo:font-weight="normal" style:font-size-asian="11pt" style:language-asian="zxx" + style:country-asian="none" style:font-weight-asian="normal" + style:font-size-complex="11pt" style:language-complex="zxx" + style:country-complex="none" style:font-weight-complex="normal"/> + </style:style> + <style:style style:name="T25" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="zxx" fo:country="none" + fo:font-weight="normal" fo:background-color="#ffffff" loext:char-shading-value="0" + style:font-size-asian="11pt" style:language-asian="zxx" style:country-asian="none" + style:font-weight-asian="normal" style:font-size-complex="11pt" + style:language-complex="zxx" style:country-complex="none" + style:font-weight-complex="normal"/> + </style:style> + <style:style style:name="T26" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="zxx" fo:country="none" + style:font-size-asian="11pt" style:language-asian="zxx" style:country-asian="none" + style:font-size-complex="11pt" style:language-complex="zxx" + style:country-complex="none"/> + </style:style> + <style:style style:name="T27" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="zxx" fo:country="none" + fo:background-color="#ffffff" loext:char-shading-value="0" + style:font-size-asian="11pt" style:language-asian="zxx" style:country-asian="none" + style:font-size-complex="11pt" style:language-complex="zxx" + style:country-complex="none"/> + </style:style> + <style:style style:name="T28" style:family="text"> + <style:text-properties fo:text-shadow="none" fo:background-color="transparent" + loext:char-shading-value="0"/> + </style:style> + <style:style style:name="T29" style:family="text"> + <style:text-properties fo:text-shadow="none" officeooo:rsid="0022c3f8" fo:background-color="transparent" + loext:char-shading-value="0" style:font-weight-complex="normal"/> + </style:style> + <style:style style:name="T30" style:family="text"> + <style:text-properties style:use-window-font-color="true" style:font-name="Calibri" fo:font-size="11pt" + fo:language="zxx" fo:country="none" fo:text-shadow="none" fo:font-weight="normal" + fo:background-color="transparent" loext:char-shading-value="0" + style:font-size-asian="11pt" style:language-asian="zxx" style:country-asian="none" + style:font-weight-asian="normal" style:font-size-complex="11pt" + style:language-complex="zxx" style:country-complex="none" + style:font-weight-complex="normal"/> + </style:style> + <style:style style:name="T31" style:family="text"> + <style:text-properties style:use-window-font-color="true" style:font-name="Calibri" fo:font-size="11pt" + fo:language="en" fo:country="US" fo:text-shadow="none" officeooo:rsid="0022c3f8" + fo:background-color="transparent" loext:char-shading-value="0" + style:font-size-asian="11pt" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="T32" style:family="text"> + <style:text-properties style:use-window-font-color="true" style:font-name="Calibri" fo:font-size="11pt" + fo:language="en" fo:country="US" fo:text-shadow="none" officeooo:rsid="0023b666" + fo:background-color="transparent" loext:char-shading-value="0" + style:font-size-asian="11pt" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="T33" style:family="text"> + <style:text-properties style:use-window-font-color="true" style:font-name="Calibri" fo:font-size="11pt" + fo:language="en" fo:country="US" fo:text-shadow="none" officeooo:rsid="0022c3f8" + fo:background-color="transparent" loext:char-shading-value="0" + style:font-size-asian="11pt" style:font-size-complex="11pt" + style:font-weight-complex="normal"/> + </style:style> + <style:style style:name="T34" style:family="text"> + <style:text-properties fo:language="zxx" fo:country="none" style:language-asian="zxx" + style:country-asian="none" style:language-complex="zxx" + style:country-complex="none"/> + </style:style> + <style:style style:name="T35" style:family="text"> + <style:text-properties officeooo:rsid="00560a1d"/> + </style:style> + <text:list-style style:name="L1"> + <text:list-level-style-number text:level="1" text:style-name="WW_5f_CharLFO19LVL1" style:num-suffix="." + style:num-format="1"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab" fo:text-indent="-0.25in" + fo:margin-left="0.5in"/> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number text:level="2" style:num-suffix="." style:num-format="a" + style:num-letter-sync="true"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab" fo:text-indent="-0.25in" + fo:margin-left="1in"/> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number text:level="3" style:num-suffix="." style:num-format="i"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment" + fo:text-align="end"> + <style:list-level-label-alignment text:label-followed-by="listtab" fo:text-indent="-0.1252in" + fo:margin-left="1.5in"/> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number text:level="4" style:num-suffix="." style:num-format="1"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab" fo:text-indent="-0.25in" + fo:margin-left="2in"/> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number text:level="5" style:num-suffix="." style:num-format="a" + style:num-letter-sync="true"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab" fo:text-indent="-0.25in" + fo:margin-left="2.5in"/> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number text:level="6" style:num-suffix="." style:num-format="i"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment" + fo:text-align="end"> + <style:list-level-label-alignment text:label-followed-by="listtab" fo:text-indent="-0.1252in" + fo:margin-left="3in"/> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number text:level="7" style:num-suffix="." style:num-format="1"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab" fo:text-indent="-0.25in" + fo:margin-left="3.5in"/> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number text:level="8" style:num-suffix="." style:num-format="a" + style:num-letter-sync="true"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab" fo:text-indent="-0.25in" + fo:margin-left="4in"/> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number text:level="9" style:num-suffix="." style:num-format="i"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment" + fo:text-align="end"> + <style:list-level-label-alignment text:label-followed-by="listtab" fo:text-indent="-0.1252in" + fo:margin-left="4.5in"/> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number text:level="10" style:num-suffix="." style:num-format="1"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab" + text:list-tab-stop-position="2.75in" fo:text-indent="-0.25in" + fo:margin-left="2.75in"/> + </style:list-level-properties> + </text:list-level-style-number> + </text:list-style> + </office:automatic-styles> + <office:body> + <office:text> + <office:forms form:automatic-focus="false" form:apply-design-mode="false"/> + <text:sequence-decls> + <text:sequence-decl text:display-outline-level="0" text:name="Illustration"/> + <text:sequence-decl text:display-outline-level="0" text:name="Table"/> + <text:sequence-decl text:display-outline-level="0" text:name="Text"/> + <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/> + <text:sequence-decl text:display-outline-level="0" text:name="Figure"/> + </text:sequence-decls> + <text:p text:style-name="P5">Anmeldung an das Handelsregisteramt</text:p> + <text:p text:style-name="P4"/> + <text:list xml:id="list47114456" text:style-name="WWNum6"> + <text:list-item> + <text:p text:style-name="P35"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T7">Zur Eintragung in das Handelsregister wird folgende + Neueintragung angemeldet: + </text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P38"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P38"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Firma</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:bookmark-start text:name="FirmaGerman"/> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.FirmaGerman</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T10">}}</text:span> + </text:span> + <text:bookmark-end text:name="FirmaGerman"/> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T10"></text:span> + </text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">AG</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Übersetzungen der Firma</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.FirmaGerman</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}} SA</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.FirmaGerman</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}} Ltd</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Sitz</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.HeadquarterRegisteredOffice</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}} / {{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.HeadquarterCanton</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}}</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Domizil</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P14"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.HeadquarterZIP</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}} {{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.HeadquarterCity</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}}, {{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.HeadquarterStreet</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}} {{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.HeadquarterStreetNumber</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}} (eigenes Rechtsdomizil)</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Rechtsform</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7">Aktiengesellschaft</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Statutendatum</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:span text:style-name="Fett"> + <text:span text:style-name="T11">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.DateOfStatutes</text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T11">}}</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Zweck</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P36"> + <text:span text:style-name="Fett"> + <text:span text:style-name="T25">{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">%</text:span> + <text:span text:style-name="ProxeusCode">if input.PurposeDETemplate == ‘Other‘</text:span> + <text:span text:style-name="ProxeusFormula">%}</text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T25">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.PurposeDE</text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T25">}} {</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">%</text:span> + <text:span text:style-name="ProxeusCode">else</text:span> + <text:span text:style-name="ProxeusFormula">%}</text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T25">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.PurposeDETemplate</text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T25">}} {</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">%</text:span> + <text:span text:style-name="ProxeusCode">endif</text:span> + <text:span text:style-name="ProxeusFormula">%}</text:span> + </text:p> + </text:list-item> + </text:list> + <text:p text:style-name="P37"> + <text:span text:style-name="ProxeusFormula"/> + </text:p> + </office:text> + </office:body> +</office:document-content> \ No newline at end of file diff --git a/src/test/resources/content_fixed.xml b/src/test/resources/content_fixed.xml new file mode 100644 index 0000000..01e3001 --- /dev/null +++ b/src/test/resources/content_fixed.xml @@ -0,0 +1,707 @@ +<?xml version="1.0" encoding="UTF-8"?> +<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2"> + <office:scripts></office:scripts> + <office:font-face-decls> + <style:font-face style:name="Symbol" style:font-charset="x-symbol" style:font-pitch="variable" style:font-family-generic="roman" svg:font-family="Symbol"></style:font-face> + <style:font-face style:name="Wingdings" style:font-charset="x-symbol" style:font-pitch="variable" style:font-family-generic="system" svg:font-family="Wingdings"></style:font-face> + <style:font-face style:name="Univers LT 45 Light" style:font-family-generic="roman" svg:font-family="'Univers LT 45 Light'"></style:font-face> + <style:font-face style:name="The Sans Semi Bold" style:font-family-generic="swiss" svg:font-family="'The Sans Semi Bold'"></style:font-face> + <style:font-face style:name="Courier New" style:font-pitch="fixed" style:font-family-generic="modern" svg:font-family="'Courier New'"></style:font-face> + <style:font-face style:name="LinePrinter" style:font-pitch="fixed" style:font-family-generic="modern" svg:font-family="LinePrinter"></style:font-face> + <style:font-face style:name="Arial1" style:font-pitch="variable" style:font-family-generic="roman" svg:font-family="Arial"></style:font-face> + <style:font-face style:name="Arial Unicode MS" style:font-pitch="variable" style:font-family-generic="roman" svg:font-family="'Arial Unicode MS'"></style:font-face> + <style:font-face style:name="Liberation Serif" style:font-pitch="variable" style:font-family-generic="roman" svg:font-family="'Liberation Serif'"></style:font-face> + <style:font-face style:name="Times New Roman" style:font-pitch="variable" style:font-family-generic="roman" svg:font-family="'Times New Roman'"></style:font-face> + <style:font-face style:name="Arial" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="Arial"></style:font-face> + <style:font-face style:name="Calibri" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="Calibri"></style:font-face> + <style:font-face style:name="Calibri1" style:font-adornments="Regular" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="Calibri"></style:font-face> + <style:font-face style:name="Helv" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="Helv"></style:font-face> + <style:font-face style:name="Liberation Sans" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="'Liberation Sans'"></style:font-face> + <style:font-face style:name="Tahoma" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="Tahoma"></style:font-face> + <style:font-face style:name="MS Gothic" style:font-pitch="variable" style:font-family-generic="system" svg:font-family="'MS Gothic'"></style:font-face> + <style:font-face style:name="Tahoma1" style:font-pitch="variable" style:font-family-generic="system" svg:font-family="Tahoma"></style:font-face> + <style:font-face style:name="Univers 45 Light" style:font-pitch="variable" style:font-family-generic="system" svg:font-family="'Univers 45 Light'"></style:font-face> + </office:font-face-decls> + <office:automatic-styles> + <style:style style:name="P1" style:parent-style-name="Text_20_body" style:family="paragraph" style:master-page-name=""> + <style:paragraph-properties fo:border-left="none" fo:padding="0.0193in" fo:border-top="0.06pt solid #000000" style:line-height-at-least="0.1528in" style:join-border="false" fo:border-right="none" fo:border-bottom="none" fo:hyphenation-ladder-count="no-limit" style:page-number="auto"> + <style:tab-stops> + <style:tab-stop style:position="5.9028in" style:type="right"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties fo:hyphenation-push-char-count="2" style:font-name="Calibri" loext:padding-bottom="0in" loext:padding-right="0in" fo:hyphenation-remain-char-count="2" officeooo:rsid="004b6859" loext:padding-top="0.0193in" fo:hyphenate="true" loext:border="none" loext:padding-left="0in"></style:text-properties> + </style:style> + <style:style style:name="P2" style:parent-style-name="Footer" style:family="paragraph"> + <style:paragraph-properties fo:padding-left="0in" fo:border-left="none" fo:padding-top="0.0138in" fo:border-top="0.51pt solid #000000" fo:border-right="none" fo:padding-right="0in" fo:border-bottom="none" fo:padding-bottom="0in" style:shadow="none"> + <style:tab-stops> + <style:tab-stop style:position="5.8083in" style:type="center"></style:tab-stop> + <style:tab-stop style:position="5.9063in" style:type="right"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="001fc62c"></style:text-properties> + </style:style> + <style:style style:name="P3" style:parent-style-name="Footer" style:family="paragraph"> + <style:paragraph-properties fo:padding-left="0in" fo:border-left="none" fo:padding-top="0.0138in" fo:border-top="0.51pt solid #000000" fo:border-right="none" fo:padding-right="0in" fo:border-bottom="none" fo:padding-bottom="0in" style:shadow="none"> + <style:tab-stops> + <style:tab-stop style:position="5.8083in" style:type="center"></style:tab-stop> + <style:tab-stop style:position="5.9063in" style:type="right"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0022fa95"></style:text-properties> + </style:style> + <style:style style:name="P4" style:parent-style-name="Standard" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.25in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:country-asian="US" fo:country="DE" style:language-asian="en" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P5" style:parent-style-name="Standard" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.25in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:country-asian="US" fo:country="DE" style:language-asian="en" officeooo:rsid="00346b24" style:font-size-complex="10pt" fo:font-size="16pt" style:font-size-asian="10pt" fo:language="de" officeooo:paragraph-rsid="00346b24"></style:text-properties> + </style:style> + <style:style style:name="P6" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" fo:country="DE" style:font-size-complex="11pt" style:font-weight-complex="bold" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P7" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:country="DE" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P8" style:parent-style-name="Standard1" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:country="DE" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P9" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P10" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="00560a1d"></style:text-properties> + </style:style> + <style:style style:name="P11" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="004cc6b6"></style:text-properties> + </style:style> + <style:style style:name="P12" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="00465c76"></style:text-properties> + </style:style> + <style:style style:name="P13" style:parent-style-name="Standard1" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="00560a1d"></style:text-properties> + </style:style> + <style:style style:name="P14" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P15" style:parent-style-name="List_20_Paragraph" style:list-style-name="WWNum6" style:family="paragraph"> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" style:font-name-complex="Calibri" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P16" style:parent-style-name="Body_20_Text" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" style:font-name-complex="Arial" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P17" style:parent-style-name="Body_20_Text" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" style:font-name-complex="Arial" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P18" style:parent-style-name="Body_20_Text" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" style:font-size-complex="11pt" style:font-weight-complex="bold" fo:font-size="11pt" style:font-size-asian="11pt" style:font-name-complex="Arial" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P19" style:parent-style-name="Body_20_Text" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P20" style:parent-style-name="Body_20_Text" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P21" style:parent-style-name="Body_20_Text" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P22" style:parent-style-name="Body_20_Text" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P23" style:parent-style-name="Body_20_Text" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" style:font-name-complex="Arial" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P24" style:parent-style-name="Body_20_Text" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" style:font-name-complex="Arial" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P25" style:parent-style-name="Body_20_Text" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P26" style:parent-style-name="Body_20_Text" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P27" style:parent-style-name="Body_20_Text" style:list-style-name="L1" style:family="paragraph"> + <style:paragraph-properties fo:text-indent="-0.2138in" fo:margin-left="0.2236in" fo:margin-bottom="0in" style:auto-text-indent="false" fo:margin-right="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"> + <style:tab-stops></style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P28" style:parent-style-name="Body_20_Text" style:list-style-name="L1" style:family="paragraph"> + <style:paragraph-properties fo:text-indent="-0.2138in" fo:margin-left="0.2236in" fo:margin-bottom="0in" style:auto-text-indent="false" fo:margin-right="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"> + <style:tab-stops></style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P29" style:parent-style-name="Body_20_Text" style:list-style-name="L1" style:family="paragraph"> + <style:paragraph-properties fo:text-indent="-0.2138in" fo:margin-left="0.2236in" fo:margin-bottom="0in" style:auto-text-indent="false" fo:margin-right="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"> + <style:tab-stops></style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:background-color="#ffff00" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P30" style:parent-style-name="Body_20_Text" style:family="paragraph"> + <style:paragraph-properties fo:text-indent="0in" fo:margin-left="0in" fo:margin-bottom="0in" style:auto-text-indent="false" fo:margin-right="0in" fo:margin-top="0.1929in" loext:contextual-spacing="false"></style:paragraph-properties> + </style:style> + <style:style style:name="P31" style:parent-style-name="Normal" style:family="paragraph"> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" style:font-name-complex="Calibri" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P32" style:parent-style-name="Normal" style:family="paragraph"> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P33" style:parent-style-name="Normal" style:family="paragraph"> + <style:paragraph-properties> + <style:tab-stops> + <style:tab-stop style:position="2.9535in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="00465c76"></style:text-properties> + </style:style> + <style:style style:name="P34" style:parent-style-name="Normal" style:family="paragraph"> + <style:paragraph-properties> + <style:tab-stops> + <style:tab-stop style:position="2.9535in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="004cc6b6"></style:text-properties> + </style:style> + <style:style style:name="P35" style:parent-style-name="Standard" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.25in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P36" style:parent-style-name="Standard" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P37" style:parent-style-name="Standard" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in" style:justify-single-word="false" fo:text-align="justify"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P38" style:parent-style-name="Standard" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.25in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:country-asian="US" fo:country="DE" style:language-asian="en" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P39" style:parent-style-name="Standard" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in" style:justify-single-word="false" fo:orphans="0" fo:text-align="justify" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:country="DE" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P40" style:parent-style-name="Text_20_body" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.139in" fo:margin-bottom="0.1181in" fo:margin-top="0in" loext:contextual-spacing="false"></style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P41" style:parent-style-name="Text_20_body" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.139in" fo:margin-bottom="0.1181in" fo:margin-top="0in" loext:contextual-spacing="false"></style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="T1" style:family="text"> + <style:text-properties fo:font-size="9pt"></style:text-properties> + </style:style> + <style:style style:name="T2" style:family="text"> + <style:text-properties officeooo:rsid="003c7b76" fo:font-size="9pt"></style:text-properties> + </style:style> + <style:style style:name="T3" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="9pt" style:font-size-asian="9pt" style:font-name-complex="Arial"></style:text-properties> + </style:style> + <style:style style:name="T4" style:family="text"> + <style:text-properties style:font-name="Calibri" style:font-size-complex="9pt" fo:font-size="9pt" style:font-size-asian="9pt" style:font-name-complex="Arial"></style:text-properties> + </style:style> + <style:style style:name="T5" style:family="text"> + <style:text-properties style:font-name="Calibri" officeooo:rsid="002dfa47" style:font-size-complex="9pt" fo:font-size="9pt" style:font-size-asian="9pt" style:font-name-complex="Arial"></style:text-properties> + </style:style> + <style:style style:name="T6" style:family="text"> + <style:text-properties style:font-name="Calibri" officeooo:rsid="002dfa47" fo:font-size="9pt" style:font-size-asian="9pt" style:font-name-complex="Arial"></style:text-properties> + </style:style> + <style:style style:name="T7" style:family="text"> + <style:text-properties style:font-name="Calibri" style:country-asian="US" fo:country="DE" style:language-asian="en" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties> + </style:style> + <style:style style:name="T8" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:country="DE" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties> + </style:style> + <style:style style:name="T9" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:country="DE" style:font-size-complex="11pt" style:font-weight-complex="bold" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties> + </style:style> + <style:style style:name="T10" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:country="DE" officeooo:rsid="00580dab" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties> + </style:style> + <style:style style:name="T11" style:family="text"> + <style:text-properties loext:char-shading-value="0" style:font-name="Calibri" style:font-weight-asian="normal" fo:font-weight="normal" fo:country="DE" fo:background-color="#ffffff" style:font-size-complex="11pt" style:font-weight-complex="normal" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties> + </style:style> + <style:style style:name="T12" style:family="text"> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" fo:country="DE" style:font-size-complex="11pt" style:font-weight-complex="bold" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties> + </style:style> + <style:style style:name="T13" style:family="text"> + <style:text-properties loext:char-shading-value="0" style:font-name="Calibri" fo:country="DE" fo:background-color="#ffffff" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties> + </style:style> + <style:style style:name="T14" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:country="US" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="en"></style:text-properties> + </style:style> + <style:style style:name="T15" style:family="text"> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" fo:country="US" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" style:font-name-complex="Arial" fo:language="en"></style:text-properties> + </style:style> + <style:style style:name="T16" style:family="text"> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" fo:country="US" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="en"></style:text-properties> + </style:style> + <style:style style:name="T17" style:family="text"> + <style:text-properties loext:char-shading-value="0" style:font-name="Calibri" fo:country="US" fo:background-color="#ffffff" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="en"></style:text-properties> + </style:style> + <style:style style:name="T18" style:family="text"> + <style:text-properties loext:char-shading-value="0" style:language-complex="zxx" style:font-name="Calibri" style:country-asian="none" fo:country="US" style:language-asian="zxx" style:country-complex="none" fo:background-color="#ffffff" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="en"></style:text-properties> + </style:style> + <style:style style:name="T19" style:family="text"> + <style:text-properties style:font-name="Calibri" style:country-asian="none" style:font-weight-asian="normal" style:language-asian="zxx" style:country-complex="none" fo:background-color="#ffffff" style:font-size-complex="11pt" style:font-weight-complex="normal" style:font-size-asian="11pt" loext:char-shading-value="0" style:language-complex="zxx" fo:font-weight="normal" fo:country="US" fo:font-size="11pt" fo:language="en"></style:text-properties> + </style:style> + <style:style style:name="T20" style:family="text"> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" style:font-name-complex="Arial"></style:text-properties> + </style:style> + <style:style style:name="T21" style:family="text"> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt"></style:text-properties> + </style:style> + <style:style style:name="T22" style:family="text"> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" style:font-name-complex="Arial"></style:text-properties> + </style:style> + <style:style style:name="T23" style:family="text"> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt"></style:text-properties> + </style:style> + <style:style style:name="T24" style:family="text"> + <style:text-properties style:font-name="Calibri" style:country-asian="none" style:font-weight-asian="normal" style:language-asian="zxx" style:country-complex="none" style:font-size-complex="11pt" style:font-weight-complex="normal" style:font-size-asian="11pt" style:language-complex="zxx" fo:font-weight="normal" fo:country="none" fo:font-size="11pt" fo:language="zxx"></style:text-properties> + </style:style> + <style:style style:name="T25" style:family="text"> + <style:text-properties style:font-name="Calibri" style:country-asian="none" style:font-weight-asian="normal" style:language-asian="zxx" style:country-complex="none" fo:background-color="#ffffff" style:font-size-complex="11pt" style:font-weight-complex="normal" style:font-size-asian="11pt" loext:char-shading-value="0" style:language-complex="zxx" fo:font-weight="normal" fo:country="none" fo:font-size="11pt" fo:language="zxx"></style:text-properties> + </style:style> + <style:style style:name="T26" style:family="text"> + <style:text-properties style:language-complex="zxx" style:font-name="Calibri" style:country-asian="none" fo:country="none" style:language-asian="zxx" style:country-complex="none" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="zxx"></style:text-properties> + </style:style> + <style:style style:name="T27" style:family="text"> + <style:text-properties loext:char-shading-value="0" style:language-complex="zxx" style:font-name="Calibri" style:country-asian="none" fo:country="none" style:language-asian="zxx" style:country-complex="none" fo:background-color="#ffffff" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="zxx"></style:text-properties> + </style:style> + <style:style style:name="T28" style:family="text"> + <style:text-properties loext:char-shading-value="0" fo:background-color="transparent" fo:text-shadow="none"></style:text-properties> + </style:style> + <style:style style:name="T29" style:family="text"> + <style:text-properties loext:char-shading-value="0" fo:background-color="transparent" fo:text-shadow="none" officeooo:rsid="0022c3f8" style:font-weight-complex="normal"></style:text-properties> + </style:style> + <style:style style:name="T30" style:family="text"> + <style:text-properties style:font-name="Calibri" style:country-asian="none" style:font-weight-asian="normal" style:language-asian="zxx" style:country-complex="none" fo:background-color="transparent" fo:text-shadow="none" style:font-size-complex="11pt" style:font-weight-complex="normal" style:font-size-asian="11pt" loext:char-shading-value="0" style:language-complex="zxx" fo:font-weight="normal" fo:country="none" fo:font-size="11pt" style:use-window-font-color="true" fo:language="zxx"></style:text-properties> + </style:style> + <style:style style:name="T31" style:family="text"> + <style:text-properties loext:char-shading-value="0" style:font-name="Calibri" fo:country="US" fo:background-color="transparent" fo:text-shadow="none" officeooo:rsid="0022c3f8" style:font-size-complex="11pt" fo:font-size="11pt" style:use-window-font-color="true" style:font-size-asian="11pt" fo:language="en"></style:text-properties> + </style:style> + <style:style style:name="T32" style:family="text"> + <style:text-properties loext:char-shading-value="0" style:font-name="Calibri" fo:country="US" fo:background-color="transparent" fo:text-shadow="none" officeooo:rsid="0023b666" style:font-size-complex="11pt" fo:font-size="11pt" style:use-window-font-color="true" style:font-size-asian="11pt" fo:language="en"></style:text-properties> + </style:style> + <style:style style:name="T33" style:family="text"> + <style:text-properties loext:char-shading-value="0" style:font-name="Calibri" fo:country="US" fo:background-color="transparent" fo:text-shadow="none" officeooo:rsid="0022c3f8" style:font-size-complex="11pt" style:font-weight-complex="normal" fo:font-size="11pt" style:use-window-font-color="true" style:font-size-asian="11pt" fo:language="en"></style:text-properties> + </style:style> + <style:style style:name="T34" style:family="text"> + <style:text-properties style:language-complex="zxx" style:country-asian="none" fo:country="none" style:language-asian="zxx" style:country-complex="none" fo:language="zxx"></style:text-properties> + </style:style> + <style:style style:name="T35" style:family="text"> + <style:text-properties officeooo:rsid="00560a1d"></style:text-properties> + </style:style> + <text:list-style style:name="L1"> + <text:list-level-style-number text:style-name="WW_5f_CharLFO19LVL1" style:num-suffix="." style:num-format="1" text:level="1"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment fo:text-indent="-0.25in" text:label-followed-by="listtab" fo:margin-left="0.5in"></style:list-level-label-alignment> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number style:num-letter-sync="true" style:num-suffix="." style:num-format="a" text:level="2"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment fo:text-indent="-0.25in" text:label-followed-by="listtab" fo:margin-left="1in"></style:list-level-label-alignment> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number style:num-suffix="." style:num-format="i" text:level="3"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment" fo:text-align="end"> + <style:list-level-label-alignment fo:text-indent="-0.1252in" text:label-followed-by="listtab" fo:margin-left="1.5in"></style:list-level-label-alignment> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number style:num-suffix="." style:num-format="1" text:level="4"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment fo:text-indent="-0.25in" text:label-followed-by="listtab" fo:margin-left="2in"></style:list-level-label-alignment> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number style:num-letter-sync="true" style:num-suffix="." style:num-format="a" text:level="5"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment fo:text-indent="-0.25in" text:label-followed-by="listtab" fo:margin-left="2.5in"></style:list-level-label-alignment> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number style:num-suffix="." style:num-format="i" text:level="6"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment" fo:text-align="end"> + <style:list-level-label-alignment fo:text-indent="-0.1252in" text:label-followed-by="listtab" fo:margin-left="3in"></style:list-level-label-alignment> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number style:num-suffix="." style:num-format="1" text:level="7"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment fo:text-indent="-0.25in" text:label-followed-by="listtab" fo:margin-left="3.5in"></style:list-level-label-alignment> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number style:num-letter-sync="true" style:num-suffix="." style:num-format="a" text:level="8"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment fo:text-indent="-0.25in" text:label-followed-by="listtab" fo:margin-left="4in"></style:list-level-label-alignment> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number style:num-suffix="." style:num-format="i" text:level="9"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment" fo:text-align="end"> + <style:list-level-label-alignment fo:text-indent="-0.1252in" text:label-followed-by="listtab" fo:margin-left="4.5in"></style:list-level-label-alignment> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number style:num-suffix="." style:num-format="1" text:level="10"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment fo:text-indent="-0.25in" text:label-followed-by="listtab" fo:margin-left="2.75in" text:list-tab-stop-position="2.75in"></style:list-level-label-alignment> + </style:list-level-properties> + </text:list-level-style-number> + </text:list-style> + </office:automatic-styles> + <office:body> + <office:text> + <office:forms form:automatic-focus="false" form:apply-design-mode="false"></office:forms> + <text:sequence-decls> + <text:sequence-decl text:name="Illustration" text:display-outline-level="0"></text:sequence-decl> + <text:sequence-decl text:name="Table" text:display-outline-level="0"></text:sequence-decl> + <text:sequence-decl text:name="Text" text:display-outline-level="0"></text:sequence-decl> + <text:sequence-decl text:name="Drawing" text:display-outline-level="0"></text:sequence-decl> + <text:sequence-decl text:name="Figure" text:display-outline-level="0"></text:sequence-decl> + </text:sequence-decls> + <text:p text:style-name="P5">Anmeldung an das Handelsregisteramt</text:p> + <text:p text:style-name="P4"></text:p> + <text:list text:style-name="WWNum6" xml:id="list47114456"> + <text:list-item> + <text:p text:style-name="P35"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T7">Zur Eintragung in das Handelsregister wird folgende + Neueintragung angemeldet: + </text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P38"></text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P38"></text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Firma</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:bookmark-start text:name="FirmaGerman"></text:bookmark-start> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8"></text:span></text:span>{{ input.FirmaGerman }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T10"></text:span> + </text:span> + <text:bookmark-end text:name="FirmaGerman"></text:bookmark-end> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T10"></text:span> + </text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">AG</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7"></text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Übersetzungen der Firma</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8"></text:span></text:span>{{ input.FirmaGerman }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> SA</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8"></text:span></text:span>{{ input.FirmaGerman }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> Ltd</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7"></text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Sitz</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8"></text:span></text:span>{{ input.HeadquarterRegisteredOffice }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> / </text:span></text:span>{{ input.HeadquarterCanton }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"></text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7"></text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Domizil</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P14"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8"></text:span></text:span>{{ input.HeadquarterZIP }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> </text:span></text:span>{{ input.HeadquarterCity }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8">, </text:span></text:span>{{ input.HeadquarterStreet }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> </text:span></text:span>{{ input.HeadquarterStreetNumber }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> (eigenes Rechtsdomizil)</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6"></text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Rechtsform</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7">Aktiengesellschaft</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7"></text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Statutendatum</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:span text:style-name="Fett"> + <text:span text:style-name="T11"></text:span></text:span>{{ input.DateOfStatutes }}<text:span text:style-name="Fett"><text:span text:style-name="T11"></text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7"></text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Zweck</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P36"> + <text:span text:style-name="Fett"> + <text:span text:style-name="T25"></text:span></text:span>{% if input.PurposeDETemplate == ‘Other‘ %}<text:span text:style-name="ProxeusFormula"></text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T25"></text:span></text:span>{{ input.PurposeDE }}<text:span text:style-name="Fett"><text:span text:style-name="T25"> </text:span></text:span>{% else %}<text:span text:style-name="ProxeusFormula"></text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T25"></text:span></text:span>{{ input.PurposeDETemplate }}<text:span text:style-name="Fett"><text:span text:style-name="T25"> </text:span></text:span>{% endif %}<text:span text:style-name="ProxeusFormula"></text:span> + </text:p> + </text:list-item> + </text:list> + <text:p text:style-name="P37"> + <text:span text:style-name="ProxeusFormula"></text:span> + </text:p> + </office:text> + </office:body> +</office:document-content> diff --git a/src/test/resources/content_fixed_cleaned.xml b/src/test/resources/content_fixed_cleaned.xml new file mode 100644 index 0000000..77b561d --- /dev/null +++ b/src/test/resources/content_fixed_cleaned.xml @@ -0,0 +1,707 @@ +<?xml version="1.0" encoding="UTF-8"?> +<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2"> + <office:scripts></office:scripts> + <office:font-face-decls> + <style:font-face style:name="Symbol" style:font-charset="x-symbol" style:font-pitch="variable" style:font-family-generic="roman" svg:font-family="Symbol"></style:font-face> + <style:font-face style:name="Wingdings" style:font-charset="x-symbol" style:font-pitch="variable" style:font-family-generic="system" svg:font-family="Wingdings"></style:font-face> + <style:font-face style:name="Univers LT 45 Light" style:font-family-generic="roman" svg:font-family="'Univers LT 45 Light'"></style:font-face> + <style:font-face style:name="The Sans Semi Bold" style:font-family-generic="swiss" svg:font-family="'The Sans Semi Bold'"></style:font-face> + <style:font-face style:name="Courier New" style:font-pitch="fixed" style:font-family-generic="modern" svg:font-family="'Courier New'"></style:font-face> + <style:font-face style:name="LinePrinter" style:font-pitch="fixed" style:font-family-generic="modern" svg:font-family="LinePrinter"></style:font-face> + <style:font-face style:name="Arial1" style:font-pitch="variable" style:font-family-generic="roman" svg:font-family="Arial"></style:font-face> + <style:font-face style:name="Arial Unicode MS" style:font-pitch="variable" style:font-family-generic="roman" svg:font-family="'Arial Unicode MS'"></style:font-face> + <style:font-face style:name="Liberation Serif" style:font-pitch="variable" style:font-family-generic="roman" svg:font-family="'Liberation Serif'"></style:font-face> + <style:font-face style:name="Times New Roman" style:font-pitch="variable" style:font-family-generic="roman" svg:font-family="'Times New Roman'"></style:font-face> + <style:font-face style:name="Arial" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="Arial"></style:font-face> + <style:font-face style:name="Calibri" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="Calibri"></style:font-face> + <style:font-face style:name="Calibri1" style:font-adornments="Regular" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="Calibri"></style:font-face> + <style:font-face style:name="Helv" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="Helv"></style:font-face> + <style:font-face style:name="Liberation Sans" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="'Liberation Sans'"></style:font-face> + <style:font-face style:name="Tahoma" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="Tahoma"></style:font-face> + <style:font-face style:name="MS Gothic" style:font-pitch="variable" style:font-family-generic="system" svg:font-family="'MS Gothic'"></style:font-face> + <style:font-face style:name="Tahoma1" style:font-pitch="variable" style:font-family-generic="system" svg:font-family="Tahoma"></style:font-face> + <style:font-face style:name="Univers 45 Light" style:font-pitch="variable" style:font-family-generic="system" svg:font-family="'Univers 45 Light'"></style:font-face> + </office:font-face-decls> + <office:automatic-styles> + <style:style style:name="P1" style:parent-style-name="Text_20_body" style:family="paragraph" style:master-page-name=""> + <style:paragraph-properties fo:border-left="none" fo:padding="0.0193in" fo:border-top="0.06pt solid #000000" style:line-height-at-least="0.1528in" style:join-border="false" fo:border-right="none" fo:border-bottom="none" fo:hyphenation-ladder-count="no-limit" style:page-number="auto"> + <style:tab-stops> + <style:tab-stop style:position="5.9028in" style:type="right"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties fo:hyphenation-push-char-count="2" style:font-name="Calibri" loext:padding-bottom="0in" loext:padding-right="0in" fo:hyphenation-remain-char-count="2" officeooo:rsid="004b6859" loext:padding-top="0.0193in" fo:hyphenate="true" loext:border="none" loext:padding-left="0in"></style:text-properties> + </style:style> + <style:style style:name="P2" style:parent-style-name="Footer" style:family="paragraph"> + <style:paragraph-properties fo:padding-left="0in" fo:border-left="none" fo:padding-top="0.0138in" fo:border-top="0.51pt solid #000000" fo:border-right="none" fo:padding-right="0in" fo:border-bottom="none" fo:padding-bottom="0in" style:shadow="none"> + <style:tab-stops> + <style:tab-stop style:position="5.8083in" style:type="center"></style:tab-stop> + <style:tab-stop style:position="5.9063in" style:type="right"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="001fc62c"></style:text-properties> + </style:style> + <style:style style:name="P3" style:parent-style-name="Footer" style:family="paragraph"> + <style:paragraph-properties fo:padding-left="0in" fo:border-left="none" fo:padding-top="0.0138in" fo:border-top="0.51pt solid #000000" fo:border-right="none" fo:padding-right="0in" fo:border-bottom="none" fo:padding-bottom="0in" style:shadow="none"> + <style:tab-stops> + <style:tab-stop style:position="5.8083in" style:type="center"></style:tab-stop> + <style:tab-stop style:position="5.9063in" style:type="right"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0022fa95"></style:text-properties> + </style:style> + <style:style style:name="P4" style:parent-style-name="Standard" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.25in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:country-asian="US" fo:country="DE" style:language-asian="en" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P5" style:parent-style-name="Standard" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.25in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:country-asian="US" fo:country="DE" style:language-asian="en" officeooo:rsid="00346b24" style:font-size-complex="10pt" fo:font-size="16pt" style:font-size-asian="10pt" fo:language="de" officeooo:paragraph-rsid="00346b24"></style:text-properties> + </style:style> + <style:style style:name="P6" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" fo:country="DE" style:font-size-complex="11pt" style:font-weight-complex="bold" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P7" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:country="DE" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P8" style:parent-style-name="Standard1" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:country="DE" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P9" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P10" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="00560a1d"></style:text-properties> + </style:style> + <style:style style:name="P11" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="004cc6b6"></style:text-properties> + </style:style> + <style:style style:name="P12" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="00465c76"></style:text-properties> + </style:style> + <style:style style:name="P13" style:parent-style-name="Standard1" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="00560a1d"></style:text-properties> + </style:style> + <style:style style:name="P14" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P15" style:parent-style-name="List_20_Paragraph" style:list-style-name="WWNum6" style:family="paragraph"> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" style:font-name-complex="Calibri" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P16" style:parent-style-name="Body_20_Text" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" style:font-name-complex="Arial" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P17" style:parent-style-name="Body_20_Text" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" style:font-name-complex="Arial" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P18" style:parent-style-name="Body_20_Text" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" style:font-size-complex="11pt" style:font-weight-complex="bold" fo:font-size="11pt" style:font-size-asian="11pt" style:font-name-complex="Arial" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P19" style:parent-style-name="Body_20_Text" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P20" style:parent-style-name="Body_20_Text" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P21" style:parent-style-name="Body_20_Text" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P22" style:parent-style-name="Body_20_Text" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P23" style:parent-style-name="Body_20_Text" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" style:font-name-complex="Arial" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P24" style:parent-style-name="Body_20_Text" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" style:font-name-complex="Arial" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P25" style:parent-style-name="Body_20_Text" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P26" style:parent-style-name="Body_20_Text" style:family="paragraph"> + <style:paragraph-properties fo:margin-bottom="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"></style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P27" style:parent-style-name="Body_20_Text" style:list-style-name="L1" style:family="paragraph"> + <style:paragraph-properties fo:text-indent="-0.2138in" fo:margin-left="0.2236in" fo:margin-bottom="0in" style:auto-text-indent="false" fo:margin-right="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"> + <style:tab-stops></style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P28" style:parent-style-name="Body_20_Text" style:list-style-name="L1" style:family="paragraph"> + <style:paragraph-properties fo:text-indent="-0.2138in" fo:margin-left="0.2236in" fo:margin-bottom="0in" style:auto-text-indent="false" fo:margin-right="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"> + <style:tab-stops></style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P29" style:parent-style-name="Body_20_Text" style:list-style-name="L1" style:family="paragraph"> + <style:paragraph-properties fo:text-indent="-0.2138in" fo:margin-left="0.2236in" fo:margin-bottom="0in" style:auto-text-indent="false" fo:margin-right="0in" fo:margin-top="0in" loext:contextual-spacing="false" fo:line-height="100%"> + <style:tab-stops></style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:background-color="#ffff00" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P30" style:parent-style-name="Body_20_Text" style:family="paragraph"> + <style:paragraph-properties fo:text-indent="0in" fo:margin-left="0in" fo:margin-bottom="0in" style:auto-text-indent="false" fo:margin-right="0in" fo:margin-top="0.1929in" loext:contextual-spacing="false"></style:paragraph-properties> + </style:style> + <style:style style:name="P31" style:parent-style-name="Normal" style:family="paragraph"> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" style:font-name-complex="Calibri" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P32" style:parent-style-name="Normal" style:family="paragraph"> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P33" style:parent-style-name="Normal" style:family="paragraph"> + <style:paragraph-properties> + <style:tab-stops> + <style:tab-stop style:position="2.9535in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="00465c76"></style:text-properties> + </style:style> + <style:style style:name="P34" style:parent-style-name="Normal" style:family="paragraph"> + <style:paragraph-properties> + <style:tab-stops> + <style:tab-stop style:position="2.9535in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="004cc6b6"></style:text-properties> + </style:style> + <style:style style:name="P35" style:parent-style-name="Standard" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.25in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P36" style:parent-style-name="Standard" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P37" style:parent-style-name="Standard" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in" style:justify-single-word="false" fo:text-align="justify"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P38" style:parent-style-name="Standard" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.25in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:country-asian="US" fo:country="DE" style:language-asian="en" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P39" style:parent-style-name="Standard" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.1665in" style:justify-single-word="false" fo:orphans="0" fo:text-align="justify" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0in"></style:tab-stop> + <style:tab-stop style:position="0.3335in"></style:tab-stop> + <style:tab-stop style:position="3.5425in"></style:tab-stop> + <style:tab-stop style:position="3.9335in"></style:tab-stop> + <style:tab-stop style:position="4.4252in"></style:tab-stop> + <style:tab-stop style:position="4.9165in"></style:tab-stop> + <style:tab-stop style:position="5.4083in"></style:tab-stop> + <style:tab-stop style:position="5.9in"></style:tab-stop> + <style:tab-stop style:position="6.3917in"></style:tab-stop> + <style:tab-stop style:position="6.5in"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:country="DE" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P40" style:parent-style-name="Text_20_body" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.139in" fo:margin-bottom="0.1181in" fo:margin-top="0in" loext:contextual-spacing="false"></style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P41" style:parent-style-name="Text_20_body" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.139in" fo:margin-bottom="0.1181in" fo:margin-top="0in" loext:contextual-spacing="false"></style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="T1" style:family="text"> + <style:text-properties fo:font-size="9pt"></style:text-properties> + </style:style> + <style:style style:name="T2" style:family="text"> + <style:text-properties officeooo:rsid="003c7b76" fo:font-size="9pt"></style:text-properties> + </style:style> + <style:style style:name="T3" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="9pt" style:font-size-asian="9pt" style:font-name-complex="Arial"></style:text-properties> + </style:style> + <style:style style:name="T4" style:family="text"> + <style:text-properties style:font-name="Calibri" style:font-size-complex="9pt" fo:font-size="9pt" style:font-size-asian="9pt" style:font-name-complex="Arial"></style:text-properties> + </style:style> + <style:style style:name="T5" style:family="text"> + <style:text-properties style:font-name="Calibri" officeooo:rsid="002dfa47" style:font-size-complex="9pt" fo:font-size="9pt" style:font-size-asian="9pt" style:font-name-complex="Arial"></style:text-properties> + </style:style> + <style:style style:name="T6" style:family="text"> + <style:text-properties style:font-name="Calibri" officeooo:rsid="002dfa47" fo:font-size="9pt" style:font-size-asian="9pt" style:font-name-complex="Arial"></style:text-properties> + </style:style> + <style:style style:name="T7" style:family="text"> + <style:text-properties style:font-name="Calibri" style:country-asian="US" fo:country="DE" style:language-asian="en" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties> + </style:style> + <style:style style:name="T8" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:country="DE" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties> + </style:style> + <style:style style:name="T9" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:country="DE" style:font-size-complex="11pt" style:font-weight-complex="bold" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties> + </style:style> + <style:style style:name="T10" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:country="DE" officeooo:rsid="00580dab" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties> + </style:style> + <style:style style:name="T11" style:family="text"> + <style:text-properties loext:char-shading-value="0" style:font-name="Calibri" style:font-weight-asian="normal" fo:font-weight="normal" fo:country="DE" fo:background-color="#ffffff" style:font-size-complex="11pt" style:font-weight-complex="normal" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties> + </style:style> + <style:style style:name="T12" style:family="text"> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" fo:country="DE" style:font-size-complex="11pt" style:font-weight-complex="bold" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties> + </style:style> + <style:style style:name="T13" style:family="text"> + <style:text-properties loext:char-shading-value="0" style:font-name="Calibri" fo:country="DE" fo:background-color="#ffffff" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties> + </style:style> + <style:style style:name="T14" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:country="US" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="en"></style:text-properties> + </style:style> + <style:style style:name="T15" style:family="text"> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" fo:country="US" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" style:font-name-complex="Arial" fo:language="en"></style:text-properties> + </style:style> + <style:style style:name="T16" style:family="text"> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" fo:country="US" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="en"></style:text-properties> + </style:style> + <style:style style:name="T17" style:family="text"> + <style:text-properties loext:char-shading-value="0" style:font-name="Calibri" fo:country="US" fo:background-color="#ffffff" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="en"></style:text-properties> + </style:style> + <style:style style:name="T18" style:family="text"> + <style:text-properties loext:char-shading-value="0" style:language-complex="zxx" style:font-name="Calibri" style:country-asian="none" fo:country="US" style:language-asian="zxx" style:country-complex="none" fo:background-color="#ffffff" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="en"></style:text-properties> + </style:style> + <style:style style:name="T19" style:family="text"> + <style:text-properties style:font-name="Calibri" style:country-asian="none" style:font-weight-asian="normal" style:language-asian="zxx" style:country-complex="none" fo:background-color="#ffffff" style:font-size-complex="11pt" style:font-weight-complex="normal" style:font-size-asian="11pt" loext:char-shading-value="0" style:language-complex="zxx" fo:font-weight="normal" fo:country="US" fo:font-size="11pt" fo:language="en"></style:text-properties> + </style:style> + <style:style style:name="T20" style:family="text"> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" style:font-name-complex="Arial"></style:text-properties> + </style:style> + <style:style style:name="T21" style:family="text"> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt"></style:text-properties> + </style:style> + <style:style style:name="T22" style:family="text"> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" style:font-name-complex="Arial"></style:text-properties> + </style:style> + <style:style style:name="T23" style:family="text"> + <style:text-properties style:font-name="Calibri" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt"></style:text-properties> + </style:style> + <style:style style:name="T24" style:family="text"> + <style:text-properties style:font-name="Calibri" style:country-asian="none" style:font-weight-asian="normal" style:language-asian="zxx" style:country-complex="none" style:font-size-complex="11pt" style:font-weight-complex="normal" style:font-size-asian="11pt" style:language-complex="zxx" fo:font-weight="normal" fo:country="none" fo:font-size="11pt" fo:language="zxx"></style:text-properties> + </style:style> + <style:style style:name="T25" style:family="text"> + <style:text-properties style:font-name="Calibri" style:country-asian="none" style:font-weight-asian="normal" style:language-asian="zxx" style:country-complex="none" fo:background-color="#ffffff" style:font-size-complex="11pt" style:font-weight-complex="normal" style:font-size-asian="11pt" loext:char-shading-value="0" style:language-complex="zxx" fo:font-weight="normal" fo:country="none" fo:font-size="11pt" fo:language="zxx"></style:text-properties> + </style:style> + <style:style style:name="T26" style:family="text"> + <style:text-properties style:language-complex="zxx" style:font-name="Calibri" style:country-asian="none" fo:country="none" style:language-asian="zxx" style:country-complex="none" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="zxx"></style:text-properties> + </style:style> + <style:style style:name="T27" style:family="text"> + <style:text-properties loext:char-shading-value="0" style:language-complex="zxx" style:font-name="Calibri" style:country-asian="none" fo:country="none" style:language-asian="zxx" style:country-complex="none" fo:background-color="#ffffff" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="zxx"></style:text-properties> + </style:style> + <style:style style:name="T28" style:family="text"> + <style:text-properties loext:char-shading-value="0" fo:background-color="transparent" fo:text-shadow="none"></style:text-properties> + </style:style> + <style:style style:name="T29" style:family="text"> + <style:text-properties loext:char-shading-value="0" fo:background-color="transparent" fo:text-shadow="none" officeooo:rsid="0022c3f8" style:font-weight-complex="normal"></style:text-properties> + </style:style> + <style:style style:name="T30" style:family="text"> + <style:text-properties style:font-name="Calibri" style:country-asian="none" style:font-weight-asian="normal" style:language-asian="zxx" style:country-complex="none" fo:background-color="transparent" fo:text-shadow="none" style:font-size-complex="11pt" style:font-weight-complex="normal" style:font-size-asian="11pt" loext:char-shading-value="0" style:language-complex="zxx" fo:font-weight="normal" fo:country="none" fo:font-size="11pt" style:use-window-font-color="true" fo:language="zxx"></style:text-properties> + </style:style> + <style:style style:name="T31" style:family="text"> + <style:text-properties loext:char-shading-value="0" style:font-name="Calibri" fo:country="US" fo:background-color="transparent" fo:text-shadow="none" officeooo:rsid="0022c3f8" style:font-size-complex="11pt" fo:font-size="11pt" style:use-window-font-color="true" style:font-size-asian="11pt" fo:language="en"></style:text-properties> + </style:style> + <style:style style:name="T32" style:family="text"> + <style:text-properties loext:char-shading-value="0" style:font-name="Calibri" fo:country="US" fo:background-color="transparent" fo:text-shadow="none" officeooo:rsid="0023b666" style:font-size-complex="11pt" fo:font-size="11pt" style:use-window-font-color="true" style:font-size-asian="11pt" fo:language="en"></style:text-properties> + </style:style> + <style:style style:name="T33" style:family="text"> + <style:text-properties loext:char-shading-value="0" style:font-name="Calibri" fo:country="US" fo:background-color="transparent" fo:text-shadow="none" officeooo:rsid="0022c3f8" style:font-size-complex="11pt" style:font-weight-complex="normal" fo:font-size="11pt" style:use-window-font-color="true" style:font-size-asian="11pt" fo:language="en"></style:text-properties> + </style:style> + <style:style style:name="T34" style:family="text"> + <style:text-properties style:language-complex="zxx" style:country-asian="none" fo:country="none" style:language-asian="zxx" style:country-complex="none" fo:language="zxx"></style:text-properties> + </style:style> + <style:style style:name="T35" style:family="text"> + <style:text-properties officeooo:rsid="00560a1d"></style:text-properties> + </style:style> + <text:list-style style:name="L1"> + <text:list-level-style-number text:style-name="WW_5f_CharLFO19LVL1" style:num-suffix="." style:num-format="1" text:level="1"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment fo:text-indent="-0.25in" text:label-followed-by="listtab" fo:margin-left="0.5in"></style:list-level-label-alignment> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number style:num-letter-sync="true" style:num-suffix="." style:num-format="a" text:level="2"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment fo:text-indent="-0.25in" text:label-followed-by="listtab" fo:margin-left="1in"></style:list-level-label-alignment> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number style:num-suffix="." style:num-format="i" text:level="3"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment" fo:text-align="end"> + <style:list-level-label-alignment fo:text-indent="-0.1252in" text:label-followed-by="listtab" fo:margin-left="1.5in"></style:list-level-label-alignment> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number style:num-suffix="." style:num-format="1" text:level="4"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment fo:text-indent="-0.25in" text:label-followed-by="listtab" fo:margin-left="2in"></style:list-level-label-alignment> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number style:num-letter-sync="true" style:num-suffix="." style:num-format="a" text:level="5"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment fo:text-indent="-0.25in" text:label-followed-by="listtab" fo:margin-left="2.5in"></style:list-level-label-alignment> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number style:num-suffix="." style:num-format="i" text:level="6"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment" fo:text-align="end"> + <style:list-level-label-alignment fo:text-indent="-0.1252in" text:label-followed-by="listtab" fo:margin-left="3in"></style:list-level-label-alignment> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number style:num-suffix="." style:num-format="1" text:level="7"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment fo:text-indent="-0.25in" text:label-followed-by="listtab" fo:margin-left="3.5in"></style:list-level-label-alignment> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number style:num-letter-sync="true" style:num-suffix="." style:num-format="a" text:level="8"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment fo:text-indent="-0.25in" text:label-followed-by="listtab" fo:margin-left="4in"></style:list-level-label-alignment> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number style:num-suffix="." style:num-format="i" text:level="9"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment" fo:text-align="end"> + <style:list-level-label-alignment fo:text-indent="-0.1252in" text:label-followed-by="listtab" fo:margin-left="4.5in"></style:list-level-label-alignment> + </style:list-level-properties> + </text:list-level-style-number> + <text:list-level-style-number style:num-suffix="." style:num-format="1" text:level="10"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment fo:text-indent="-0.25in" text:label-followed-by="listtab" fo:margin-left="2.75in" text:list-tab-stop-position="2.75in"></style:list-level-label-alignment> + </style:list-level-properties> + </text:list-level-style-number> + </text:list-style> + </office:automatic-styles> + <office:body> + <office:text> + <office:forms form:automatic-focus="false" form:apply-design-mode="false"></office:forms> + <text:sequence-decls> + <text:sequence-decl text:name="Illustration" text:display-outline-level="0"></text:sequence-decl> + <text:sequence-decl text:name="Table" text:display-outline-level="0"></text:sequence-decl> + <text:sequence-decl text:name="Text" text:display-outline-level="0"></text:sequence-decl> + <text:sequence-decl text:name="Drawing" text:display-outline-level="0"></text:sequence-decl> + <text:sequence-decl text:name="Figure" text:display-outline-level="0"></text:sequence-decl> + </text:sequence-decls> + <text:p text:style-name="P5">Anmeldung an das Handelsregisteramt</text:p> + + <text:list text:style-name="WWNum6" xml:id="list47114456"> + <text:list-item> + <text:p text:style-name="P35"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T7">Zur Eintragung in das Handelsregister wird folgende + Neueintragung angemeldet: + </text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + + </text:list-item> + <text:list-item> + + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Firma</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:bookmark-start text:name="FirmaGerman"></text:bookmark-start> + <text:span text:style-name="Absatz-Standardschriftart"> + </text:span>{{ input.FirmaGerman }}<text:span text:style-name="Absatz-Standardschriftart"> + </text:span> + <text:bookmark-end text:name="FirmaGerman"></text:bookmark-end> + <text:span text:style-name="Absatz-Standardschriftart"> + + </text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">AG</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Übersetzungen der Firma</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:span text:style-name="Absatz-Standardschriftart"> + </text:span>{{ input.FirmaGerman }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> SA</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:span text:style-name="Absatz-Standardschriftart"> + </text:span>{{ input.FirmaGerman }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> Ltd</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Sitz</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:span text:style-name="Absatz-Standardschriftart"> + </text:span>{{ input.HeadquarterRegisteredOffice }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> / </text:span></text:span>{{ input.HeadquarterCanton }}<text:span text:style-name="Absatz-Standardschriftart"> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Domizil</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P14"> + <text:span text:style-name="Absatz-Standardschriftart"> + </text:span>{{ input.HeadquarterZIP }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> </text:span></text:span>{{ input.HeadquarterCity }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8">, </text:span></text:span>{{ input.HeadquarterStreet }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> </text:span></text:span>{{ input.HeadquarterStreetNumber }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> (eigenes Rechtsdomizil)</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Rechtsform</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7">Aktiengesellschaft</text:p> + </text:list-item> + <text:list-item> + + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Statutendatum</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:span text:style-name="Fett"> + </text:span>{{ input.DateOfStatutes }}<text:span text:style-name="Fett"> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Zweck</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P36"> + <text:span text:style-name="Fett"> + </text:span>{% if input.PurposeDETemplate == ‘Other‘ %} + <text:span text:style-name="Fett"> + </text:span>{{ input.PurposeDE }}<text:span text:style-name="Fett"><text:span text:style-name="T25"> </text:span></text:span>{% else %} + <text:span text:style-name="Fett"> + </text:span>{{ input.PurposeDETemplate }}<text:span text:style-name="Fett"><text:span text:style-name="T25"> </text:span></text:span>{% endif %} + </text:p> + </text:list-item> + </text:list> + <text:p text:style-name="P37"> + + </text:p> + </office:text> + </office:body> +</office:document-content> \ No newline at end of file diff --git a/src/test/resources/content_noif_fixed_cleaned.xml b/src/test/resources/content_noif_fixed_cleaned.xml new file mode 100644 index 0000000..efccaf5 --- /dev/null +++ b/src/test/resources/content_noif_fixed_cleaned.xml @@ -0,0 +1,3 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document-content xmlns:officeooo="http://openoffice.org/2009/office" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" office:version="1.2"><office:scripts></office:scripts><office:font-face-decls><style:font-face style:name="Symbol" style:font-charset="x-symbol" style:font-pitch="variable" style:font-family-generic="roman" svg:font-family="Symbol"></style:font-face><style:font-face style:name="Wingdings" style:font-charset="x-symbol" style:font-pitch="variable" style:font-family-generic="system" svg:font-family="Wingdings"></style:font-face><style:font-face style:name="Univers LT 45 Light" style:font-family-generic="roman" svg:font-family="'Univers LT 45 Light'"></style:font-face><style:font-face style:name="The Sans Semi Bold" style:font-family-generic="swiss" svg:font-family="'The Sans Semi Bold'"></style:font-face><style:font-face style:name="Courier New" style:font-pitch="fixed" style:font-family-generic="modern" svg:font-family="'Courier New'"></style:font-face><style:font-face style:name="LinePrinter" style:font-pitch="fixed" style:font-family-generic="modern" svg:font-family="LinePrinter"></style:font-face><style:font-face style:name="Arial" style:font-pitch="variable" style:font-family-generic="roman" svg:font-family="Arial"></style:font-face><style:font-face style:name="Arial Unicode MS" style:font-pitch="variable" style:font-family-generic="roman" svg:font-family="'Arial Unicode MS'"></style:font-face><style:font-face style:name="Liberation Serif" style:font-pitch="variable" style:font-family-generic="roman" svg:font-family="'Liberation Serif'"></style:font-face><style:font-face style:name="Times New Roman" style:font-pitch="variable" style:font-family-generic="roman" svg:font-family="'Times New Roman'"></style:font-face><style:font-face style:name="Arial1" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="Arial"></style:font-face><style:font-face style:name="Calibri" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="Calibri"></style:font-face><style:font-face style:name="Calibri1" style:font-adornments="Regular" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="Calibri"></style:font-face><style:font-face style:name="Helv" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="Helv"></style:font-face><style:font-face style:name="Liberation Sans" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="'Liberation Sans'"></style:font-face><style:font-face style:name="Tahoma" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="Tahoma"></style:font-face><style:font-face style:name="MS Gothic" style:font-pitch="variable" style:font-family-generic="system" svg:font-family="'MS Gothic'"></style:font-face><style:font-face style:name="Tahoma1" style:font-pitch="variable" style:font-family-generic="system" svg:font-family="Tahoma"></style:font-face><style:font-face style:name="Univers 45 Light" style:font-pitch="variable" style:font-family-generic="system" svg:font-family="'Univers 45 Light'"></style:font-face></office:font-face-decls><office:automatic-styles><style:style style:name="P1" style:parent-style-name="Text_20_body" style:family="paragraph" style:master-page-name=""><style:paragraph-properties fo:border-left="none" fo:padding="0.049cm" fo:border-top="0.06pt solid #000000" style:line-height-at-least="0.388cm" style:join-border="false" fo:border-right="none" fo:border-bottom="none" fo:hyphenation-ladder-count="no-limit" style:page-number="auto"><style:tab-stops><style:tab-stop style:position="14.993cm" style:type="right"></style:tab-stop></style:tab-stops></style:paragraph-properties><style:text-properties fo:hyphenation-push-char-count="2" style:font-name="Calibri" loext:padding-bottom="0cm" loext:padding-right="0cm" fo:hyphenation-remain-char-count="2" officeooo:rsid="004b6859" loext:padding-top="0.049cm" fo:hyphenate="true" loext:border="none" loext:padding-left="0cm"></style:text-properties></style:style><style:style style:name="P2" style:parent-style-name="Footer" style:family="paragraph"><style:paragraph-properties fo:padding-left="0cm" fo:border-left="none" fo:padding-top="0.035cm" fo:border-top="0.51pt solid #000000" fo:border-right="none" fo:padding-right="0cm" fo:border-bottom="none" fo:padding-bottom="0cm" style:shadow="none"><style:tab-stops><style:tab-stop style:position="14.753cm" style:type="center"></style:tab-stop><style:tab-stop style:position="15.002cm" style:type="right"></style:tab-stop></style:tab-stops></style:paragraph-properties><style:text-properties officeooo:paragraph-rsid="001fc62c"></style:text-properties></style:style><style:style style:name="P3" style:parent-style-name="Footer" style:family="paragraph"><style:paragraph-properties fo:padding-left="0cm" fo:border-left="none" fo:padding-top="0.035cm" fo:border-top="0.51pt solid #000000" fo:border-right="none" fo:padding-right="0cm" fo:border-bottom="none" fo:padding-bottom="0cm" style:shadow="none"><style:tab-stops><style:tab-stop style:position="14.753cm" style:type="center"></style:tab-stop><style:tab-stop style:position="15.002cm" style:type="right"></style:tab-stop></style:tab-stops></style:paragraph-properties><style:text-properties officeooo:paragraph-rsid="0022fa95"></style:text-properties></style:style><style:style style:name="P4" style:parent-style-name="Standard" style:family="paragraph"><style:paragraph-properties style:line-height-at-least="0.423cm" fo:orphans="0" fo:widows="0"><style:tab-stops><style:tab-stop style:position="0cm"></style:tab-stop><style:tab-stop style:position="0.635cm"></style:tab-stop><style:tab-stop style:position="8.998cm"></style:tab-stop><style:tab-stop style:position="9.991cm"></style:tab-stop><style:tab-stop style:position="11.24cm"></style:tab-stop><style:tab-stop style:position="12.488cm"></style:tab-stop><style:tab-stop style:position="13.737cm"></style:tab-stop><style:tab-stop style:position="14.986cm"></style:tab-stop><style:tab-stop style:position="16.235cm"></style:tab-stop><style:tab-stop style:position="16.51cm"></style:tab-stop></style:tab-stops></style:paragraph-properties><style:text-properties style:font-name="Calibri" style:country-asian="US" fo:country="DE" style:language-asian="en" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de" officeooo:paragraph-rsid="0032fef0"></style:text-properties></style:style><style:style style:name="P5" style:parent-style-name="Standard" style:family="paragraph"><style:paragraph-properties style:line-height-at-least="0.423cm" fo:orphans="0" fo:widows="0"><style:tab-stops><style:tab-stop style:position="0cm"></style:tab-stop><style:tab-stop style:position="0.635cm"></style:tab-stop><style:tab-stop style:position="8.998cm"></style:tab-stop><style:tab-stop style:position="9.991cm"></style:tab-stop><style:tab-stop style:position="11.24cm"></style:tab-stop><style:tab-stop style:position="12.488cm"></style:tab-stop><style:tab-stop style:position="13.737cm"></style:tab-stop><style:tab-stop style:position="14.986cm"></style:tab-stop><style:tab-stop style:position="16.235cm"></style:tab-stop><style:tab-stop style:position="16.51cm"></style:tab-stop></style:tab-stops></style:paragraph-properties><style:text-properties style:font-name="Calibri" style:country-asian="US" fo:country="DE" style:language-asian="en" officeooo:rsid="00346b24" style:font-size-complex="10pt" fo:font-size="16pt" style:font-size-asian="10pt" fo:language="de" officeooo:paragraph-rsid="00346b24"></style:text-properties></style:style><style:style style:name="P6" style:parent-style-name="Standard" style:family="paragraph"><style:paragraph-properties style:line-height-at-least="0.423cm" style:justify-single-word="false" fo:text-align="justify"><style:tab-stops><style:tab-stop style:position="0cm"></style:tab-stop><style:tab-stop style:position="0.847cm"></style:tab-stop><style:tab-stop style:position="8.998cm"></style:tab-stop><style:tab-stop style:position="9.991cm"></style:tab-stop><style:tab-stop style:position="11.24cm"></style:tab-stop><style:tab-stop style:position="12.488cm"></style:tab-stop><style:tab-stop style:position="13.737cm"></style:tab-stop><style:tab-stop style:position="14.986cm"></style:tab-stop><style:tab-stop style:position="16.235cm"></style:tab-stop><style:tab-stop style:position="16.51cm"></style:tab-stop></style:tab-stops></style:paragraph-properties><style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties></style:style><style:style style:name="P7" style:parent-style-name="Standard" style:list-style-name="WWNum6" style:family="paragraph"><style:paragraph-properties style:line-height-at-least="0.423cm" fo:orphans="0" fo:widows="0"><style:tab-stops><style:tab-stop style:position="0cm"></style:tab-stop><style:tab-stop style:position="0.635cm"></style:tab-stop><style:tab-stop style:position="8.998cm"></style:tab-stop><style:tab-stop style:position="9.991cm"></style:tab-stop><style:tab-stop style:position="11.24cm"></style:tab-stop><style:tab-stop style:position="12.488cm"></style:tab-stop><style:tab-stop style:position="13.737cm"></style:tab-stop><style:tab-stop style:position="14.986cm"></style:tab-stop><style:tab-stop style:position="16.235cm"></style:tab-stop><style:tab-stop style:position="16.51cm"></style:tab-stop></style:tab-stops></style:paragraph-properties><style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties></style:style><style:style style:name="P8" style:parent-style-name="Standard" style:list-style-name="WWNum6" style:family="paragraph"><style:paragraph-properties style:line-height-at-least="0.423cm"><style:tab-stops><style:tab-stop style:position="0cm"></style:tab-stop><style:tab-stop style:position="0.847cm"></style:tab-stop><style:tab-stop style:position="8.998cm"></style:tab-stop><style:tab-stop style:position="9.991cm"></style:tab-stop><style:tab-stop style:position="11.24cm"></style:tab-stop><style:tab-stop style:position="12.488cm"></style:tab-stop><style:tab-stop style:position="13.737cm"></style:tab-stop><style:tab-stop style:position="14.986cm"></style:tab-stop><style:tab-stop style:position="16.235cm"></style:tab-stop><style:tab-stop style:position="16.51cm"></style:tab-stop></style:tab-stops></style:paragraph-properties><style:text-properties officeooo:paragraph-rsid="006c2a27"></style:text-properties></style:style><style:style style:name="P9" style:parent-style-name="Standard" style:list-style-name="WWNum6" style:family="paragraph"><style:paragraph-properties style:line-height-at-least="0.423cm" fo:orphans="0" fo:widows="0"><style:tab-stops><style:tab-stop style:position="0cm"></style:tab-stop><style:tab-stop style:position="0.635cm"></style:tab-stop><style:tab-stop style:position="8.998cm"></style:tab-stop><style:tab-stop style:position="9.991cm"></style:tab-stop><style:tab-stop style:position="11.24cm"></style:tab-stop><style:tab-stop style:position="12.488cm"></style:tab-stop><style:tab-stop style:position="13.737cm"></style:tab-stop><style:tab-stop style:position="14.986cm"></style:tab-stop><style:tab-stop style:position="16.235cm"></style:tab-stop><style:tab-stop style:position="16.51cm"></style:tab-stop></style:tab-stops></style:paragraph-properties><style:text-properties style:font-name="Calibri" style:country-asian="US" fo:country="DE" style:language-asian="en" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de" officeooo:paragraph-rsid="0032fef0"></style:text-properties></style:style><style:style style:name="P10" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"><style:paragraph-properties style:line-height-at-least="0.423cm"><style:tab-stops><style:tab-stop style:position="0cm"></style:tab-stop><style:tab-stop style:position="0.847cm"></style:tab-stop><style:tab-stop style:position="8.998cm"></style:tab-stop><style:tab-stop style:position="9.991cm"></style:tab-stop><style:tab-stop style:position="11.24cm"></style:tab-stop><style:tab-stop style:position="12.488cm"></style:tab-stop><style:tab-stop style:position="13.737cm"></style:tab-stop><style:tab-stop style:position="14.986cm"></style:tab-stop><style:tab-stop style:position="16.235cm"></style:tab-stop><style:tab-stop style:position="16.51cm"></style:tab-stop></style:tab-stops></style:paragraph-properties><style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" fo:country="DE" style:font-size-complex="11pt" style:font-weight-complex="bold" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de" officeooo:paragraph-rsid="0032fef0"></style:text-properties></style:style><style:style style:name="P11" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"><style:paragraph-properties style:line-height-at-least="0.423cm"><style:tab-stops><style:tab-stop style:position="0cm"></style:tab-stop><style:tab-stop style:position="0.847cm"></style:tab-stop><style:tab-stop style:position="8.998cm"></style:tab-stop><style:tab-stop style:position="9.991cm"></style:tab-stop><style:tab-stop style:position="11.24cm"></style:tab-stop><style:tab-stop style:position="12.488cm"></style:tab-stop><style:tab-stop style:position="13.737cm"></style:tab-stop><style:tab-stop style:position="14.986cm"></style:tab-stop><style:tab-stop style:position="16.235cm"></style:tab-stop><style:tab-stop style:position="16.51cm"></style:tab-stop></style:tab-stops></style:paragraph-properties><style:text-properties style:font-name="Calibri" fo:country="DE" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de" officeooo:paragraph-rsid="0032fef0"></style:text-properties></style:style><style:style style:name="P12" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"><style:paragraph-properties style:line-height-at-least="0.423cm"><style:tab-stops><style:tab-stop style:position="0cm"></style:tab-stop><style:tab-stop style:position="0.847cm"></style:tab-stop><style:tab-stop style:position="8.998cm"></style:tab-stop><style:tab-stop style:position="9.991cm"></style:tab-stop><style:tab-stop style:position="11.24cm"></style:tab-stop><style:tab-stop style:position="12.488cm"></style:tab-stop><style:tab-stop style:position="13.737cm"></style:tab-stop><style:tab-stop style:position="14.986cm"></style:tab-stop><style:tab-stop style:position="16.235cm"></style:tab-stop><style:tab-stop style:position="16.51cm"></style:tab-stop></style:tab-stops></style:paragraph-properties><style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties></style:style><style:style style:name="P13" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"><style:paragraph-properties style:line-height-at-least="0.423cm"><style:tab-stops><style:tab-stop style:position="0cm"></style:tab-stop></style:tab-stops></style:paragraph-properties><style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties></style:style><style:style style:name="T1" style:family="text"><style:text-properties fo:font-size="9pt"></style:text-properties></style:style><style:style style:name="T2" style:family="text"><style:text-properties officeooo:rsid="003c7b76" fo:font-size="9pt"></style:text-properties></style:style><style:style style:name="T3" style:family="text"><style:text-properties style:font-name="Calibri" fo:font-size="9pt" style:font-size-asian="9pt" style:font-name-complex="Arial1"></style:text-properties></style:style><style:style style:name="T4" style:family="text"><style:text-properties style:font-name="Calibri" style:font-size-complex="9pt" fo:font-size="9pt" style:font-size-asian="9pt" style:font-name-complex="Arial1"></style:text-properties></style:style><style:style style:name="T5" style:family="text"><style:text-properties style:font-name="Calibri" officeooo:rsid="002dfa47" style:font-size-complex="9pt" fo:font-size="9pt" style:font-size-asian="9pt" style:font-name-complex="Arial1"></style:text-properties></style:style><style:style style:name="T6" style:family="text"><style:text-properties style:font-name="Calibri" officeooo:rsid="002dfa47" fo:font-size="9pt" style:font-size-asian="9pt" style:font-name-complex="Arial1"></style:text-properties></style:style><style:style style:name="T7" style:family="text"><style:text-properties style:font-name="Calibri" style:country-asian="US" fo:country="DE" style:language-asian="en" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties></style:style><style:style style:name="T8" style:family="text"><style:text-properties style:font-name="Calibri" fo:country="DE" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties></style:style><style:style style:name="T9" style:family="text"><style:text-properties style:font-name="Calibri" fo:country="DE" officeooo:rsid="00580dab" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties></style:style><style:style style:name="T10" style:family="text"><style:text-properties loext:char-shading-value="0" style:font-name="Calibri" style:font-weight-asian="normal" fo:font-weight="normal" fo:country="DE" fo:background-color="#ffffff" style:font-size-complex="11pt" style:font-weight-complex="normal" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties></style:style><style:style style:name="T11" style:family="text"><style:text-properties style:font-name="Calibri" style:country-asian="none" style:font-weight-asian="normal" style:language-asian="zxx" style:country-complex="none" fo:background-color="#ffffff" style:font-size-complex="11pt" style:font-weight-complex="normal" style:font-size-asian="11pt" loext:char-shading-value="0" style:language-complex="zxx" fo:font-weight="normal" fo:country="none" fo:font-size="11pt" fo:language="zxx"></style:text-properties></style:style><style:style style:name="T12" style:family="text"><style:text-properties style:font-name="Calibri" style:country-asian="none" style:font-weight-asian="normal" style:language-asian="zxx" style:country-complex="none" fo:background-color="#ffffff" style:font-size-complex="11pt" style:font-weight-complex="normal" style:font-size-asian="11pt" loext:char-shading-value="0" style:language-complex="zxx" fo:font-weight="normal" fo:country="none" officeooo:rsid="006b296c" fo:font-size="11pt" fo:language="zxx"></style:text-properties></style:style><style:style style:name="T13" style:family="text"><style:text-properties officeooo:rsid="0066c213"></style:text-properties></style:style><style:style style:name="T14" style:family="text"><style:text-properties officeooo:rsid="006b296c"></style:text-properties></style:style></office:automatic-styles><office:body><office:text><office:forms form:automatic-focus="false" form:apply-design-mode="false"></office:forms><text:sequence-decls><text:sequence-decl text:name="Illustration" text:display-outline-level="0"></text:sequence-decl><text:sequence-decl text:name="Table" text:display-outline-level="0"></text:sequence-decl><text:sequence-decl text:name="Text" text:display-outline-level="0"></text:sequence-decl><text:sequence-decl text:name="Drawing" text:display-outline-level="0"></text:sequence-decl><text:sequence-decl text:name="Figure" text:display-outline-level="0"></text:sequence-decl></text:sequence-decls><text:p text:style-name="P5">Anmeldung an das Handelsregisteramt</text:p><text:p text:style-name="P4"></text:p><text:list text:style-name="WWNum6" xml:id="list220043497"><text:list-item><text:p text:style-name="P7"><text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T7">Zur Eintragung in das Handelsregister wird folgende Neueintragung angemeldet:</text:span></text:span></text:p></text:list-item><text:list-item><text:p text:style-name="P9"></text:p></text:list-item><text:list-item><text:p text:style-name="P9"></text:p></text:list-item><text:list-item><text:p text:style-name="P10">Firma</text:p></text:list-item><text:list-item><text:p text:style-name="P12"><text:bookmark-start text:name="FirmaGerman"></text:bookmark-start><text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"></text:span></text:span>testfirma<text:bookmark-end text:name="FirmaGerman"></text:bookmark-end><text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T9"> </text:span></text:span><text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8">AG</text:span></text:span></text:p></text:list-item><text:list-item><text:p text:style-name="P11"></text:p></text:list-item><text:list-item><text:p text:style-name="P10">Übersetzungen der Firma</text:p></text:list-item><text:list-item><text:p text:style-name="P12"><text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"></text:span></text:span>testfirma<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> SA</text:span></text:span></text:p></text:list-item><text:list-item><text:p text:style-name="P12"><text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"></text:span></text:span>testfirma<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> Ltd</text:span></text:span></text:p></text:list-item><text:list-item><text:p text:style-name="P11"></text:p></text:list-item><text:list-item><text:p text:style-name="P10">Sitz</text:p></text:list-item><text:list-item><text:p text:style-name="P12"><text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"></text:span></text:span>testoffice<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> / </text:span></text:span>testcanton</text:p></text:list-item><text:list-item><text:p text:style-name="P11"></text:p></text:list-item><text:list-item><text:p text:style-name="P10">Domizil</text:p></text:list-item><text:list-item><text:p text:style-name="P13"><text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"></text:span></text:span><text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> </text:span></text:span>testcity<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8">, </text:span></text:span>teststreet<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> </text:span></text:span>testnumber<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> (eigenes Rechtsdomizil)</text:span></text:span></text:p></text:list-item><text:list-item><text:p text:style-name="P10"></text:p></text:list-item><text:list-item><text:p text:style-name="P10">Rechtsform</text:p></text:list-item><text:list-item><text:p text:style-name="P11">Aktiengesellschaft</text:p></text:list-item><text:list-item><text:p text:style-name="P11"></text:p></text:list-item><text:list-item><text:p text:style-name="P10">Statutendatum</text:p></text:list-item><text:list-item><text:p text:style-name="P12"><text:span text:style-name="Fett"><text:span text:style-name="T10"></text:span></text:span></text:p></text:list-item><text:list-item><text:p text:style-name="P11"></text:p></text:list-item><text:list-item><text:p text:style-name="P10">Zweck</text:p></text:list-item><text:list-item><text:p text:style-name="P8"><text:span text:style-name="Fett"><text:span text:style-name="T12"></text:span></text:span></text:p></text:list-item></text:list><text:p text:style-name="P6"></text:p></office:text></office:body></office:document-content> \ No newline at end of file diff --git a/src/test/resources/content_with_error.xml b/src/test/resources/content_with_error.xml new file mode 100644 index 0000000..3d78d3e --- /dev/null +++ b/src/test/resources/content_with_error.xml @@ -0,0 +1,570 @@ +<?xml version="1.0" encoding="UTF-8"?> +<office:document-content xmlns:officeooo="http://openoffice.org/2009/office" + xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xforms="http://www.w3.org/2002/xforms" + xmlns:dom="http://www.w3.org/2001/xml-events" + xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" + xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" + xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:drawooo="http://openoffice.org/2010/draw" + xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" + xmlns:tableooo="http://openoffice.org/2009/table" xmlns:oooc="http://openoffice.org/2004/calc" + xmlns:ooow="http://openoffice.org/2004/writer" xmlns:css3t="http://www.w3.org/TR/css3-text/" + xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" + xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" + xmlns:rpt="http://openoffice.org/2005/report" + xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" + xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" + xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" + xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" + xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" + xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" + xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" + xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" + xmlns:ooo="http://openoffice.org/2004/office" + xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" + xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" + xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" office:version="1.2"> + <office:scripts/> + <office:font-face-decls> + <style:font-face style:name="Symbol" svg:font-family="Symbol" style:font-family-generic="roman" + style:font-pitch="variable" style:font-charset="x-symbol"/> + <style:font-face style:name="Wingdings" svg:font-family="Wingdings" style:font-family-generic="system" + style:font-pitch="variable" style:font-charset="x-symbol"/> + <style:font-face style:name="Univers LT 45 Light" svg:font-family="'Univers LT 45 Light'" + style:font-family-generic="roman"/> + <style:font-face style:name="The Sans Semi Bold" svg:font-family="'The Sans Semi Bold'" + style:font-family-generic="swiss"/> + <style:font-face style:name="Courier New" svg:font-family="'Courier New'" + style:font-family-generic="modern" style:font-pitch="fixed"/> + <style:font-face style:name="LinePrinter" svg:font-family="LinePrinter" style:font-family-generic="modern" + style:font-pitch="fixed"/> + <style:font-face style:name="Arial" svg:font-family="Arial" style:font-family-generic="roman" + style:font-pitch="variable"/> + <style:font-face style:name="Arial Unicode MS" svg:font-family="'Arial Unicode MS'" + style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" + style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Times New Roman" svg:font-family="'Times New Roman'" + style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Arial1" svg:font-family="Arial" style:font-family-generic="swiss" + style:font-pitch="variable"/> + <style:font-face style:name="Calibri" svg:font-family="Calibri" style:font-family-generic="swiss" + style:font-pitch="variable"/> + <style:font-face style:name="Calibri1" svg:font-family="Calibri" style:font-adornments="Regular" + style:font-family-generic="swiss" style:font-pitch="variable"/> + <style:font-face style:name="Helv" svg:font-family="Helv" style:font-family-generic="swiss" + style:font-pitch="variable"/> + <style:font-face style:name="Liberation Sans" svg:font-family="'Liberation Sans'" + style:font-family-generic="swiss" style:font-pitch="variable"/> + <style:font-face style:name="Tahoma" svg:font-family="Tahoma" style:font-family-generic="swiss" + style:font-pitch="variable"/> + <style:font-face style:name="MS Gothic" svg:font-family="'MS Gothic'" + style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="Tahoma1" svg:font-family="Tahoma" style:font-family-generic="system" + style:font-pitch="variable"/> + <style:font-face style:name="Univers 45 Light" svg:font-family="'Univers 45 Light'" + style:font-family-generic="system" style:font-pitch="variable"/> + </office:font-face-decls> + <office:automatic-styles> + <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Text_20_body" + style:master-page-name=""> + <style:paragraph-properties style:line-height-at-least="0.388cm" fo:hyphenation-ladder-count="no-limit" + style:page-number="auto" fo:padding="0.049cm" fo:border-left="none" + fo:border-right="none" fo:border-top="0.06pt solid #000000" + fo:border-bottom="none" style:join-border="false"> + <style:tab-stops> + <style:tab-stop style:position="14.993cm" style:type="right"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" officeooo:rsid="004b6859" loext:padding-left="0cm" + loext:padding-right="0cm" loext:padding-top="0.049cm" loext:padding-bottom="0cm" + loext:border="none" fo:hyphenate="true" fo:hyphenation-remain-char-count="2" + fo:hyphenation-push-char-count="2"/> + </style:style> + <style:style style:name="P2" style:family="paragraph" style:parent-style-name="Footer"> + <style:paragraph-properties fo:padding-left="0cm" fo:padding-right="0cm" fo:padding-top="0.035cm" + fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" + fo:border-top="0.51pt solid #000000" fo:border-bottom="none" + style:shadow="none"> + <style:tab-stops> + <style:tab-stop style:position="14.753cm" style:type="center"/> + <style:tab-stop style:position="15.002cm" style:type="right"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="001fc62c"/> + </style:style> + <style:style style:name="P3" style:family="paragraph" style:parent-style-name="Footer"> + <style:paragraph-properties fo:padding-left="0cm" fo:padding-right="0cm" fo:padding-top="0.035cm" + fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" + fo:border-top="0.51pt solid #000000" fo:border-bottom="none" + style:shadow="none"> + <style:tab-stops> + <style:tab-stop style:position="14.753cm" style:type="center"/> + <style:tab-stop style:position="15.002cm" style:type="right"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0022fa95"/> + </style:style> + <style:style style:name="P4" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties style:line-height-at-least="0.423cm" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0cm"/> + <style:tab-stop style:position="0.635cm"/> + <style:tab-stop style:position="8.998cm"/> + <style:tab-stop style:position="9.991cm"/> + <style:tab-stop style:position="11.24cm"/> + <style:tab-stop style:position="12.488cm"/> + <style:tab-stop style:position="13.737cm"/> + <style:tab-stop style:position="14.986cm"/> + <style:tab-stop style:position="16.235cm"/> + <style:tab-stop style:position="16.51cm"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + officeooo:paragraph-rsid="0032fef0" style:font-size-asian="11pt" + style:language-asian="en" style:country-asian="US" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P5" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties style:line-height-at-least="0.423cm" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0cm"/> + <style:tab-stop style:position="0.635cm"/> + <style:tab-stop style:position="8.998cm"/> + <style:tab-stop style:position="9.991cm"/> + <style:tab-stop style:position="11.24cm"/> + <style:tab-stop style:position="12.488cm"/> + <style:tab-stop style:position="13.737cm"/> + <style:tab-stop style:position="14.986cm"/> + <style:tab-stop style:position="16.235cm"/> + <style:tab-stop style:position="16.51cm"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:font-size="16pt" fo:language="de" fo:country="DE" + officeooo:rsid="00346b24" officeooo:paragraph-rsid="00346b24" + style:font-size-asian="10pt" style:language-asian="en" style:country-asian="US" + style:font-size-complex="10pt"/> + </style:style> + <style:style style:name="P6" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties style:line-height-at-least="0.423cm" fo:text-align="justify" + style:justify-single-word="false"> + <style:tab-stops> + <style:tab-stop style:position="0cm"/> + <style:tab-stop style:position="0.847cm"/> + <style:tab-stop style:position="8.998cm"/> + <style:tab-stop style:position="9.991cm"/> + <style:tab-stop style:position="11.24cm"/> + <style:tab-stop style:position="12.488cm"/> + <style:tab-stop style:position="13.737cm"/> + <style:tab-stop style:position="14.986cm"/> + <style:tab-stop style:position="16.235cm"/> + <style:tab-stop style:position="16.51cm"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"/> + </style:style> + <style:style style:name="P7" style:family="paragraph" style:parent-style-name="Standard" + style:list-style-name="WWNum6"> + <style:paragraph-properties style:line-height-at-least="0.423cm" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0cm"/> + <style:tab-stop style:position="0.635cm"/> + <style:tab-stop style:position="8.998cm"/> + <style:tab-stop style:position="9.991cm"/> + <style:tab-stop style:position="11.24cm"/> + <style:tab-stop style:position="12.488cm"/> + <style:tab-stop style:position="13.737cm"/> + <style:tab-stop style:position="14.986cm"/> + <style:tab-stop style:position="16.235cm"/> + <style:tab-stop style:position="16.51cm"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"/> + </style:style> + <style:style style:name="P8" style:family="paragraph" style:parent-style-name="Standard" + style:list-style-name="WWNum6"> + <style:paragraph-properties style:line-height-at-least="0.423cm"> + <style:tab-stops> + <style:tab-stop style:position="0cm"/> + <style:tab-stop style:position="0.847cm"/> + <style:tab-stop style:position="8.998cm"/> + <style:tab-stop style:position="9.991cm"/> + <style:tab-stop style:position="11.24cm"/> + <style:tab-stop style:position="12.488cm"/> + <style:tab-stop style:position="13.737cm"/> + <style:tab-stop style:position="14.986cm"/> + <style:tab-stop style:position="16.235cm"/> + <style:tab-stop style:position="16.51cm"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"/> + </style:style> + <style:style style:name="P9" style:family="paragraph" style:parent-style-name="Standard" + style:list-style-name="WWNum6"> + <style:paragraph-properties style:line-height-at-least="0.423cm" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0cm"/> + <style:tab-stop style:position="0.635cm"/> + <style:tab-stop style:position="8.998cm"/> + <style:tab-stop style:position="9.991cm"/> + <style:tab-stop style:position="11.24cm"/> + <style:tab-stop style:position="12.488cm"/> + <style:tab-stop style:position="13.737cm"/> + <style:tab-stop style:position="14.986cm"/> + <style:tab-stop style:position="16.235cm"/> + <style:tab-stop style:position="16.51cm"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + officeooo:paragraph-rsid="0032fef0" style:font-size-asian="11pt" + style:language-asian="en" style:country-asian="US" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P10" style:family="paragraph" style:parent-style-name="Standard1" + style:list-style-name="WWNum6"> + <style:paragraph-properties style:line-height-at-least="0.423cm"> + <style:tab-stops> + <style:tab-stop style:position="0cm"/> + <style:tab-stop style:position="0.847cm"/> + <style:tab-stop style:position="8.998cm"/> + <style:tab-stop style:position="9.991cm"/> + <style:tab-stop style:position="11.24cm"/> + <style:tab-stop style:position="12.488cm"/> + <style:tab-stop style:position="13.737cm"/> + <style:tab-stop style:position="14.986cm"/> + <style:tab-stop style:position="16.235cm"/> + <style:tab-stop style:position="16.51cm"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + fo:font-weight="bold" officeooo:paragraph-rsid="0032fef0" + style:font-size-asian="11pt" style:font-weight-asian="bold" + style:font-size-complex="11pt" style:font-weight-complex="bold"/> + </style:style> + <style:style style:name="P11" style:family="paragraph" style:parent-style-name="Standard1" + style:list-style-name="WWNum6"> + <style:paragraph-properties style:line-height-at-least="0.423cm"> + <style:tab-stops> + <style:tab-stop style:position="0cm"/> + <style:tab-stop style:position="0.847cm"/> + <style:tab-stop style:position="8.998cm"/> + <style:tab-stop style:position="9.991cm"/> + <style:tab-stop style:position="11.24cm"/> + <style:tab-stop style:position="12.488cm"/> + <style:tab-stop style:position="13.737cm"/> + <style:tab-stop style:position="14.986cm"/> + <style:tab-stop style:position="16.235cm"/> + <style:tab-stop style:position="16.51cm"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + officeooo:paragraph-rsid="0032fef0" style:font-size-asian="11pt" + style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="P12" style:family="paragraph" style:parent-style-name="Standard1" + style:list-style-name="WWNum6"> + <style:paragraph-properties style:line-height-at-least="0.423cm"> + <style:tab-stops> + <style:tab-stop style:position="0cm"/> + <style:tab-stop style:position="0.847cm"/> + <style:tab-stop style:position="8.998cm"/> + <style:tab-stop style:position="9.991cm"/> + <style:tab-stop style:position="11.24cm"/> + <style:tab-stop style:position="12.488cm"/> + <style:tab-stop style:position="13.737cm"/> + <style:tab-stop style:position="14.986cm"/> + <style:tab-stop style:position="16.235cm"/> + <style:tab-stop style:position="16.51cm"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"/> + </style:style> + <style:style style:name="P13" style:family="paragraph" style:parent-style-name="Standard1" + style:list-style-name="WWNum6"> + <style:paragraph-properties style:line-height-at-least="0.423cm"> + <style:tab-stops> + <style:tab-stop style:position="0cm"/> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"/> + </style:style> + <style:style style:name="T1" style:family="text"> + <style:text-properties fo:font-size="9pt"/> + </style:style> + <style:style style:name="T2" style:family="text"> + <style:text-properties fo:font-size="9pt" officeooo:rsid="003c7b76"/> + </style:style> + <style:style style:name="T3" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="9pt" style:font-size-asian="9pt" + style:font-name-complex="Arial1"/> + </style:style> + <style:style style:name="T4" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="9pt" style:font-size-asian="9pt" + style:font-name-complex="Arial1" style:font-size-complex="9pt"/> + </style:style> + <style:style style:name="T5" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="9pt" officeooo:rsid="002dfa47" + style:font-size-asian="9pt" style:font-name-complex="Arial1" + style:font-size-complex="9pt"/> + </style:style> + <style:style style:name="T6" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="9pt" officeooo:rsid="002dfa47" + style:font-size-asian="9pt" style:font-name-complex="Arial1"/> + </style:style> + <style:style style:name="T7" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + style:font-size-asian="11pt" style:language-asian="en" style:country-asian="US" + style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="T8" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + style:font-size-asian="11pt" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="T9" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + officeooo:rsid="00580dab" style:font-size-asian="11pt" + style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="T10" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="de" fo:country="DE" + fo:font-weight="normal" fo:background-color="#ffffff" loext:char-shading-value="0" + style:font-size-asian="11pt" style:font-weight-asian="normal" + style:font-size-complex="11pt" style:font-weight-complex="normal"/> + </style:style> + <style:style style:name="T11" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="zxx" fo:country="none" + fo:font-weight="normal" fo:background-color="#ffffff" loext:char-shading-value="0" + style:font-size-asian="11pt" style:language-asian="zxx" style:country-asian="none" + style:font-weight-asian="normal" style:font-size-complex="11pt" + style:language-complex="zxx" style:country-complex="none" + style:font-weight-complex="normal"/> + </style:style> + <style:style style:name="T12" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="11pt" fo:language="zxx" fo:country="none" + fo:font-weight="normal" officeooo:rsid="006b296c" fo:background-color="#ffffff" + loext:char-shading-value="0" style:font-size-asian="11pt" style:language-asian="zxx" + style:country-asian="none" style:font-weight-asian="normal" + style:font-size-complex="11pt" style:language-complex="zxx" + style:country-complex="none" style:font-weight-complex="normal"/> + </style:style> + <style:style style:name="T13" style:family="text"> + <style:text-properties officeooo:rsid="0066c213"/> + </style:style> + <style:style style:name="T14" style:family="text"> + <style:text-properties officeooo:rsid="006b296c"/> + </style:style> + </office:automatic-styles> + <office:body> + <office:text> + <office:forms form:automatic-focus="false" form:apply-design-mode="false"/> + <text:sequence-decls> + <text:sequence-decl text:display-outline-level="0" text:name="Illustration"/> + <text:sequence-decl text:display-outline-level="0" text:name="Table"/> + <text:sequence-decl text:display-outline-level="0" text:name="Text"/> + <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/> + <text:sequence-decl text:display-outline-level="0" text:name="Figure"/> + </text:sequence-decls> + <text:p text:style-name="P5">Anmeldung an das Handelsregisteramt</text:p> + <text:p text:style-name="P4"/> + <text:list xml:id="list595537471" text:style-name="WWNum6"> + <text:list-item> + <text:p text:style-name="P7"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T7">Zur Eintragung in das Handelsregister wird folgende + Neueintragung angemeldet: + </text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P10">Firma</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P12"> + <text:bookmark-start text:name="FirmaGerman"/> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.FirmaGerman</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T9">}}</text:span> + </text:span> + <text:bookmark-end text:name="FirmaGerman"/> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T9"></text:span> + </text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">AG</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P11"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P10">Übersetzungen der Firma</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P12"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.FirmaGerman</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}} SA</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P12"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.FirmaGerman</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}} Ltd</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P11"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P10">Sitz</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P12"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.HeadquarterRegisteredOffice</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}} / {{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.HeadquarterCanton</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}}</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P11"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P10">Domizil</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P13"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.HeadquarterZIP</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}} {{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.HeadquarterCity</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}}, {{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.HeadquarterStreet</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}} {{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.HeadquarterStreetNumber</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}} (eigenes Rechtsdomizil)</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P10"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P10">Rechtsform</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P11">Aktiengesellschaft</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P11"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P10">Statutendatum</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P12"> + <text:span text:style-name="Fett"> + <text:span text:style-name="T10">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.DateOfStatutes</text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T10">}}</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P11"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P10">Zweck</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P8"> + <text:span text:style-name="Fett"> + <text:span text:style-name="T12">{#</text:span> + </text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T11">{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">%</text:span> + <text:span text:style-name="ProxeusCode">if</text:span> + <text:span text:style-name="ProxeusCode"> + <text:span text:style-name="T13">(</text:span> + </text:span> + <text:span text:style-name="ProxeusCode">input.PurposeDETemplate == ‘Other‘</text:span> + <text:span text:style-name="ProxeusCode"> + <text:span text:style-name="T13">)</text:span> + </text:span> + <text:span text:style-name="ProxeusCode"></text:span> + <text:span text:style-name="ProxeusFormula">%}</text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T11">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.PurposeDE</text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T11">}} {</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">%</text:span> + <text:span text:style-name="ProxeusCode">else</text:span> + <text:span text:style-name="ProxeusFormula">%}</text:span> + <text:span text:style-name="ProxeusFormula"> + <text:span text:style-name="T14">#}</text:span> + </text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T11">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.PurposeDETemplate</text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T11">}} {</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">%</text:span> + <text:span text:style-name="ProxeusCode">endif</text:span> + <text:span text:style-name="ProxeusFormula">%}</text:span> + </text:p> + </text:list-item> + </text:list> + <text:p text:style-name="P6"> + <text:span text:style-name="ProxeusFormula"/> + </text:p> + </office:text> + </office:body> +</office:document-content> \ No newline at end of file diff --git a/src/test/resources/content_with_error_fixed.xml b/src/test/resources/content_with_error_fixed.xml new file mode 100644 index 0000000..d8272da --- /dev/null +++ b/src/test/resources/content_with_error_fixed.xml @@ -0,0 +1,391 @@ +<?xml version="1.0" encoding="UTF-8"?> +<office:document-content xmlns:officeooo="http://openoffice.org/2009/office" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" office:version="1.2"> + <office:scripts></office:scripts> + <office:font-face-decls> + <style:font-face style:name="Symbol" style:font-charset="x-symbol" style:font-pitch="variable" style:font-family-generic="roman" svg:font-family="Symbol"></style:font-face> + <style:font-face style:name="Wingdings" style:font-charset="x-symbol" style:font-pitch="variable" style:font-family-generic="system" svg:font-family="Wingdings"></style:font-face> + <style:font-face style:name="Univers LT 45 Light" style:font-family-generic="roman" svg:font-family="'Univers LT 45 Light'"></style:font-face> + <style:font-face style:name="The Sans Semi Bold" style:font-family-generic="swiss" svg:font-family="'The Sans Semi Bold'"></style:font-face> + <style:font-face style:name="Courier New" style:font-pitch="fixed" style:font-family-generic="modern" svg:font-family="'Courier New'"></style:font-face> + <style:font-face style:name="LinePrinter" style:font-pitch="fixed" style:font-family-generic="modern" svg:font-family="LinePrinter"></style:font-face> + <style:font-face style:name="Arial" style:font-pitch="variable" style:font-family-generic="roman" svg:font-family="Arial"></style:font-face> + <style:font-face style:name="Arial Unicode MS" style:font-pitch="variable" style:font-family-generic="roman" svg:font-family="'Arial Unicode MS'"></style:font-face> + <style:font-face style:name="Liberation Serif" style:font-pitch="variable" style:font-family-generic="roman" svg:font-family="'Liberation Serif'"></style:font-face> + <style:font-face style:name="Times New Roman" style:font-pitch="variable" style:font-family-generic="roman" svg:font-family="'Times New Roman'"></style:font-face> + <style:font-face style:name="Arial1" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="Arial"></style:font-face> + <style:font-face style:name="Calibri" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="Calibri"></style:font-face> + <style:font-face style:name="Calibri1" style:font-adornments="Regular" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="Calibri"></style:font-face> + <style:font-face style:name="Helv" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="Helv"></style:font-face> + <style:font-face style:name="Liberation Sans" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="'Liberation Sans'"></style:font-face> + <style:font-face style:name="Tahoma" style:font-pitch="variable" style:font-family-generic="swiss" svg:font-family="Tahoma"></style:font-face> + <style:font-face style:name="MS Gothic" style:font-pitch="variable" style:font-family-generic="system" svg:font-family="'MS Gothic'"></style:font-face> + <style:font-face style:name="Tahoma1" style:font-pitch="variable" style:font-family-generic="system" svg:font-family="Tahoma"></style:font-face> + <style:font-face style:name="Univers 45 Light" style:font-pitch="variable" style:font-family-generic="system" svg:font-family="'Univers 45 Light'"></style:font-face> + </office:font-face-decls> + <office:automatic-styles> + <style:style style:name="P1" style:parent-style-name="Text_20_body" style:family="paragraph" style:master-page-name=""> + <style:paragraph-properties fo:border-left="none" fo:padding="0.049cm" fo:border-top="0.06pt solid #000000" style:line-height-at-least="0.388cm" style:join-border="false" fo:border-right="none" fo:border-bottom="none" fo:hyphenation-ladder-count="no-limit" style:page-number="auto"> + <style:tab-stops> + <style:tab-stop style:position="14.993cm" style:type="right"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties fo:hyphenation-push-char-count="2" style:font-name="Calibri" loext:padding-bottom="0cm" loext:padding-right="0cm" fo:hyphenation-remain-char-count="2" officeooo:rsid="004b6859" loext:padding-top="0.049cm" fo:hyphenate="true" loext:border="none" loext:padding-left="0cm"></style:text-properties> + </style:style> + <style:style style:name="P2" style:parent-style-name="Footer" style:family="paragraph"> + <style:paragraph-properties fo:padding-left="0cm" fo:border-left="none" fo:padding-top="0.035cm" fo:border-top="0.51pt solid #000000" fo:border-right="none" fo:padding-right="0cm" fo:border-bottom="none" fo:padding-bottom="0cm" style:shadow="none"> + <style:tab-stops> + <style:tab-stop style:position="14.753cm" style:type="center"></style:tab-stop> + <style:tab-stop style:position="15.002cm" style:type="right"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="001fc62c"></style:text-properties> + </style:style> + <style:style style:name="P3" style:parent-style-name="Footer" style:family="paragraph"> + <style:paragraph-properties fo:padding-left="0cm" fo:border-left="none" fo:padding-top="0.035cm" fo:border-top="0.51pt solid #000000" fo:border-right="none" fo:padding-right="0cm" fo:border-bottom="none" fo:padding-bottom="0cm" style:shadow="none"> + <style:tab-stops> + <style:tab-stop style:position="14.753cm" style:type="center"></style:tab-stop> + <style:tab-stop style:position="15.002cm" style:type="right"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0022fa95"></style:text-properties> + </style:style> + <style:style style:name="P4" style:parent-style-name="Standard" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.423cm" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0cm"></style:tab-stop> + <style:tab-stop style:position="0.635cm"></style:tab-stop> + <style:tab-stop style:position="8.998cm"></style:tab-stop> + <style:tab-stop style:position="9.991cm"></style:tab-stop> + <style:tab-stop style:position="11.24cm"></style:tab-stop> + <style:tab-stop style:position="12.488cm"></style:tab-stop> + <style:tab-stop style:position="13.737cm"></style:tab-stop> + <style:tab-stop style:position="14.986cm"></style:tab-stop> + <style:tab-stop style:position="16.235cm"></style:tab-stop> + <style:tab-stop style:position="16.51cm"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:country-asian="US" fo:country="DE" style:language-asian="en" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P5" style:parent-style-name="Standard" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.423cm" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0cm"></style:tab-stop> + <style:tab-stop style:position="0.635cm"></style:tab-stop> + <style:tab-stop style:position="8.998cm"></style:tab-stop> + <style:tab-stop style:position="9.991cm"></style:tab-stop> + <style:tab-stop style:position="11.24cm"></style:tab-stop> + <style:tab-stop style:position="12.488cm"></style:tab-stop> + <style:tab-stop style:position="13.737cm"></style:tab-stop> + <style:tab-stop style:position="14.986cm"></style:tab-stop> + <style:tab-stop style:position="16.235cm"></style:tab-stop> + <style:tab-stop style:position="16.51cm"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:country-asian="US" fo:country="DE" style:language-asian="en" officeooo:rsid="00346b24" style:font-size-complex="10pt" fo:font-size="16pt" style:font-size-asian="10pt" fo:language="de" officeooo:paragraph-rsid="00346b24"></style:text-properties> + </style:style> + <style:style style:name="P6" style:parent-style-name="Standard" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.423cm" style:justify-single-word="false" fo:text-align="justify"> + <style:tab-stops> + <style:tab-stop style:position="0cm"></style:tab-stop> + <style:tab-stop style:position="0.847cm"></style:tab-stop> + <style:tab-stop style:position="8.998cm"></style:tab-stop> + <style:tab-stop style:position="9.991cm"></style:tab-stop> + <style:tab-stop style:position="11.24cm"></style:tab-stop> + <style:tab-stop style:position="12.488cm"></style:tab-stop> + <style:tab-stop style:position="13.737cm"></style:tab-stop> + <style:tab-stop style:position="14.986cm"></style:tab-stop> + <style:tab-stop style:position="16.235cm"></style:tab-stop> + <style:tab-stop style:position="16.51cm"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P7" style:parent-style-name="Standard" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.423cm" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0cm"></style:tab-stop> + <style:tab-stop style:position="0.635cm"></style:tab-stop> + <style:tab-stop style:position="8.998cm"></style:tab-stop> + <style:tab-stop style:position="9.991cm"></style:tab-stop> + <style:tab-stop style:position="11.24cm"></style:tab-stop> + <style:tab-stop style:position="12.488cm"></style:tab-stop> + <style:tab-stop style:position="13.737cm"></style:tab-stop> + <style:tab-stop style:position="14.986cm"></style:tab-stop> + <style:tab-stop style:position="16.235cm"></style:tab-stop> + <style:tab-stop style:position="16.51cm"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P8" style:parent-style-name="Standard" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.423cm"> + <style:tab-stops> + <style:tab-stop style:position="0cm"></style:tab-stop> + <style:tab-stop style:position="0.847cm"></style:tab-stop> + <style:tab-stop style:position="8.998cm"></style:tab-stop> + <style:tab-stop style:position="9.991cm"></style:tab-stop> + <style:tab-stop style:position="11.24cm"></style:tab-stop> + <style:tab-stop style:position="12.488cm"></style:tab-stop> + <style:tab-stop style:position="13.737cm"></style:tab-stop> + <style:tab-stop style:position="14.986cm"></style:tab-stop> + <style:tab-stop style:position="16.235cm"></style:tab-stop> + <style:tab-stop style:position="16.51cm"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P9" style:parent-style-name="Standard" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.423cm" fo:orphans="0" fo:widows="0"> + <style:tab-stops> + <style:tab-stop style:position="0cm"></style:tab-stop> + <style:tab-stop style:position="0.635cm"></style:tab-stop> + <style:tab-stop style:position="8.998cm"></style:tab-stop> + <style:tab-stop style:position="9.991cm"></style:tab-stop> + <style:tab-stop style:position="11.24cm"></style:tab-stop> + <style:tab-stop style:position="12.488cm"></style:tab-stop> + <style:tab-stop style:position="13.737cm"></style:tab-stop> + <style:tab-stop style:position="14.986cm"></style:tab-stop> + <style:tab-stop style:position="16.235cm"></style:tab-stop> + <style:tab-stop style:position="16.51cm"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:country-asian="US" fo:country="DE" style:language-asian="en" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P10" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.423cm"> + <style:tab-stops> + <style:tab-stop style:position="0cm"></style:tab-stop> + <style:tab-stop style:position="0.847cm"></style:tab-stop> + <style:tab-stop style:position="8.998cm"></style:tab-stop> + <style:tab-stop style:position="9.991cm"></style:tab-stop> + <style:tab-stop style:position="11.24cm"></style:tab-stop> + <style:tab-stop style:position="12.488cm"></style:tab-stop> + <style:tab-stop style:position="13.737cm"></style:tab-stop> + <style:tab-stop style:position="14.986cm"></style:tab-stop> + <style:tab-stop style:position="16.235cm"></style:tab-stop> + <style:tab-stop style:position="16.51cm"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" style:font-weight-asian="bold" fo:font-weight="bold" fo:country="DE" style:font-size-complex="11pt" style:font-weight-complex="bold" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P11" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.423cm"> + <style:tab-stops> + <style:tab-stop style:position="0cm"></style:tab-stop> + <style:tab-stop style:position="0.847cm"></style:tab-stop> + <style:tab-stop style:position="8.998cm"></style:tab-stop> + <style:tab-stop style:position="9.991cm"></style:tab-stop> + <style:tab-stop style:position="11.24cm"></style:tab-stop> + <style:tab-stop style:position="12.488cm"></style:tab-stop> + <style:tab-stop style:position="13.737cm"></style:tab-stop> + <style:tab-stop style:position="14.986cm"></style:tab-stop> + <style:tab-stop style:position="16.235cm"></style:tab-stop> + <style:tab-stop style:position="16.51cm"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties style:font-name="Calibri" fo:country="DE" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de" officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P12" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.423cm"> + <style:tab-stops> + <style:tab-stop style:position="0cm"></style:tab-stop> + <style:tab-stop style:position="0.847cm"></style:tab-stop> + <style:tab-stop style:position="8.998cm"></style:tab-stop> + <style:tab-stop style:position="9.991cm"></style:tab-stop> + <style:tab-stop style:position="11.24cm"></style:tab-stop> + <style:tab-stop style:position="12.488cm"></style:tab-stop> + <style:tab-stop style:position="13.737cm"></style:tab-stop> + <style:tab-stop style:position="14.986cm"></style:tab-stop> + <style:tab-stop style:position="16.235cm"></style:tab-stop> + <style:tab-stop style:position="16.51cm"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="P13" style:parent-style-name="Standard1" style:list-style-name="WWNum6" style:family="paragraph"> + <style:paragraph-properties style:line-height-at-least="0.423cm"> + <style:tab-stops> + <style:tab-stop style:position="0cm"></style:tab-stop> + </style:tab-stops> + </style:paragraph-properties> + <style:text-properties officeooo:paragraph-rsid="0032fef0"></style:text-properties> + </style:style> + <style:style style:name="T1" style:family="text"> + <style:text-properties fo:font-size="9pt"></style:text-properties> + </style:style> + <style:style style:name="T2" style:family="text"> + <style:text-properties officeooo:rsid="003c7b76" fo:font-size="9pt"></style:text-properties> + </style:style> + <style:style style:name="T3" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:font-size="9pt" style:font-size-asian="9pt" style:font-name-complex="Arial1"></style:text-properties> + </style:style> + <style:style style:name="T4" style:family="text"> + <style:text-properties style:font-name="Calibri" style:font-size-complex="9pt" fo:font-size="9pt" style:font-size-asian="9pt" style:font-name-complex="Arial1"></style:text-properties> + </style:style> + <style:style style:name="T5" style:family="text"> + <style:text-properties style:font-name="Calibri" officeooo:rsid="002dfa47" style:font-size-complex="9pt" fo:font-size="9pt" style:font-size-asian="9pt" style:font-name-complex="Arial1"></style:text-properties> + </style:style> + <style:style style:name="T6" style:family="text"> + <style:text-properties style:font-name="Calibri" officeooo:rsid="002dfa47" fo:font-size="9pt" style:font-size-asian="9pt" style:font-name-complex="Arial1"></style:text-properties> + </style:style> + <style:style style:name="T7" style:family="text"> + <style:text-properties style:font-name="Calibri" style:country-asian="US" fo:country="DE" style:language-asian="en" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties> + </style:style> + <style:style style:name="T8" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:country="DE" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties> + </style:style> + <style:style style:name="T9" style:family="text"> + <style:text-properties style:font-name="Calibri" fo:country="DE" officeooo:rsid="00580dab" style:font-size-complex="11pt" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties> + </style:style> + <style:style style:name="T10" style:family="text"> + <style:text-properties loext:char-shading-value="0" style:font-name="Calibri" style:font-weight-asian="normal" fo:font-weight="normal" fo:country="DE" fo:background-color="#ffffff" style:font-size-complex="11pt" style:font-weight-complex="normal" fo:font-size="11pt" style:font-size-asian="11pt" fo:language="de"></style:text-properties> + </style:style> + <style:style style:name="T11" style:family="text"> + <style:text-properties style:font-name="Calibri" style:country-asian="none" style:font-weight-asian="normal" style:language-asian="zxx" style:country-complex="none" fo:background-color="#ffffff" style:font-size-complex="11pt" style:font-weight-complex="normal" style:font-size-asian="11pt" loext:char-shading-value="0" style:language-complex="zxx" fo:font-weight="normal" fo:country="none" fo:font-size="11pt" fo:language="zxx"></style:text-properties> + </style:style> + <style:style style:name="T12" style:family="text"> + <style:text-properties style:font-name="Calibri" style:country-asian="none" style:font-weight-asian="normal" style:language-asian="zxx" style:country-complex="none" fo:background-color="#ffffff" style:font-size-complex="11pt" style:font-weight-complex="normal" style:font-size-asian="11pt" loext:char-shading-value="0" style:language-complex="zxx" fo:font-weight="normal" fo:country="none" officeooo:rsid="006b296c" fo:font-size="11pt" fo:language="zxx"></style:text-properties> + </style:style> + <style:style style:name="T13" style:family="text"> + <style:text-properties officeooo:rsid="0066c213"></style:text-properties> + </style:style> + <style:style style:name="T14" style:family="text"> + <style:text-properties officeooo:rsid="006b296c"></style:text-properties> + </style:style> + </office:automatic-styles> + <office:body> + <office:text> + <office:forms form:automatic-focus="false" form:apply-design-mode="false"></office:forms> + <text:sequence-decls> + <text:sequence-decl text:name="Illustration" text:display-outline-level="0"></text:sequence-decl> + <text:sequence-decl text:name="Table" text:display-outline-level="0"></text:sequence-decl> + <text:sequence-decl text:name="Text" text:display-outline-level="0"></text:sequence-decl> + <text:sequence-decl text:name="Drawing" text:display-outline-level="0"></text:sequence-decl> + <text:sequence-decl text:name="Figure" text:display-outline-level="0"></text:sequence-decl> + </text:sequence-decls> + <text:p text:style-name="P5">Anmeldung an das Handelsregisteramt</text:p> + <text:p text:style-name="P4"></text:p> + <text:list text:style-name="WWNum6" xml:id="list595537471"> + <text:list-item> + <text:p text:style-name="P7"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T7">Zur Eintragung in das Handelsregister wird folgende + Neueintragung angemeldet: + </text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"></text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"></text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P10">Firma</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P12"> + <text:bookmark-start text:name="FirmaGerman"></text:bookmark-start> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8"></text:span></text:span>{{ input.FirmaGerman }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T9"></text:span> + </text:span> + <text:bookmark-end text:name="FirmaGerman"></text:bookmark-end> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T9"></text:span> + </text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">AG</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P11"></text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P10">Übersetzungen der Firma</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P12"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8"></text:span></text:span>{{ input.FirmaGerman }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> SA</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P12"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8"></text:span></text:span>{{ input.FirmaGerman }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> Ltd</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P11"></text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P10">Sitz</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P12"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8"></text:span></text:span>{{ input.HeadquarterRegisteredOffice }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> / </text:span></text:span>{{ input.HeadquarterCanton }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"></text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P11"></text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P10">Domizil</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P13"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8"></text:span></text:span>{{ input.HeadquarterZIP }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> </text:span></text:span>{{ input.HeadquarterCity }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8">, </text:span></text:span>{{ input.HeadquarterStreet }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> </text:span></text:span>{{ input.HeadquarterStreetNumber }}<text:span text:style-name="Absatz-Standardschriftart"><text:span text:style-name="T8"> (eigenes Rechtsdomizil)</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P10"></text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P10">Rechtsform</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P11">Aktiengesellschaft</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P11"></text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P10">Statutendatum</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P12"> + <text:span text:style-name="Fett"> + <text:span text:style-name="T10"></text:span></text:span>{{ input.DateOfStatutes }}<text:span text:style-name="Fett"><text:span text:style-name="T10"></text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P11"></text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P10">Zweck</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P8"> + <text:span text:style-name="Fett"> + <text:span text:style-name="T12"></text:span></text:span>{# { % if ( input.PurposeDETemplate == ‘Other‘ ) %} {{ input.PurposeDE }} { % else %} #}<text:span text:style-name="ProxeusFormula"><text:span text:style-name="T14"></text:span> + </text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T11"></text:span></text:span>{{ input.PurposeDETemplate }}<text:span text:style-name="Fett"><text:span text:style-name="T11"> </text:span></text:span>{% endif %}<text:span text:style-name="ProxeusFormula"></text:span> + </text:p> + </text:list-item> + </text:list> + <text:p text:style-name="P6"> + <text:span text:style-name="ProxeusFormula"></text:span> + </text:p> + </office:text> + </office:body> +</office:document-content> \ No newline at end of file diff --git a/src/test/resources/empty_element.xml b/src/test/resources/empty_element.xml new file mode 100644 index 0000000..12fbb8a --- /dev/null +++ b/src/test/resources/empty_element.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<root xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"> + <text:p> + <text:span></text:span> + </text:p> + <text:p> + <text:span>foobar</text:span> + </text:p> + <text:p> + barfoo<text:span></text:span><text:span>hello</text:span> + </text:p> +</root> \ No newline at end of file diff --git a/src/test/resources/empty_element_cleaned.xml b/src/test/resources/empty_element_cleaned.xml new file mode 100644 index 0000000..5160967 --- /dev/null +++ b/src/test/resources/empty_element_cleaned.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<root xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"> + <text:p> + + </text:p> + <text:p> + <text:span>foobar</text:span> + </text:p> + <text:p> + barfoo<text:span>hello</text:span> + </text:p> +</root> \ No newline at end of file diff --git a/src/test/resources/if_statement.xml b/src/test/resources/if_statement.xml new file mode 100644 index 0000000..c5818f5 --- /dev/null +++ b/src/test/resources/if_statement.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<list-item> + <p style-name="P36"> + <span style-name="Fett"> + <span style-name="T25">{</span> + </span> + <span style-name="ProxeusFormula">%</span> + <span style-name="ProxeusCode">if input.PurposeDETemplate == 'Other %}' </span> + <span style-name="ProxeusFormula">%}</span> + <span style-name="Fett"> + <span style-name="T25">{{</span> + </span> + <span style-name="ProxeusFormula">input.PurposeDE</span> + <span style-name="Fett"> + <span style-name="T25">}} {</span> + </span> + <span style-name="ProxeusFormula">%</span> + <span style-name="ProxeusCode">else</span> + <span style-name="ProxeusFormula">%}</span> + <span style-name="Fett"> + <span style-name="T25"> {{</span> + </span> + <span style-name="ProxeusFormula">input.PurposeDETemplate</span> + <span style-name="Fett"> + <span style-name="T25">}} {</span> + </span> + <span style-name="ProxeusFormula">%</span> + <span style-name="ProxeusCode">endif</span> + <span style-name="ProxeusFormula">%}</span> + </p> +</list-item> diff --git a/src/test/resources/if_statement_fixed.xml b/src/test/resources/if_statement_fixed.xml new file mode 100644 index 0000000..6d57ccb --- /dev/null +++ b/src/test/resources/if_statement_fixed.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<list-item> + <p style-name="P36"> + <span style-name="Fett"> + <span style-name="T25"></span></span>{% if input.PurposeDETemplate == 'Other %}' %}<span style-name="ProxeusFormula"></span> + <span style-name="Fett"> + <span style-name="T25"></span></span>{{ input.PurposeDE }}<span style-name="Fett"><span style-name="T25"> </span></span>{% else %}<span style-name="ProxeusFormula"></span> + <span style-name="Fett"> + <span style-name="T25"> </span></span>{{ input.PurposeDETemplate }}<span style-name="Fett"><span style-name="T25"> </span></span>{% endif %}<span style-name="ProxeusFormula"></span> + </p> +</list-item> diff --git a/src/test/resources/input1.xml b/src/test/resources/input1.xml new file mode 100644 index 0000000..767f284 --- /dev/null +++ b/src/test/resources/input1.xml @@ -0,0 +1,30 @@ +<list-item> + <p style-name="P36"> + <span style-name="Fett"> + <span style-name="T25">{</span> + </span> + <span style-name="ProxeusFormula">%</span> + <span style-name="ProxeusCode">if input.PurposeDETemplate == ‘Other‘ </span> + <span style-name="ProxeusFormula">%}</span> + <span style-name="Fett"> + <span style-name="T25">{{ + + input.PurposeDE + + }} {</span> + </span> + <span style-name="ProxeusFormula">%</span> + <span style-name="ProxeusCode">else</span> + <span style-name="ProxeusFormula">%}</span> + <span style-name="Fett"> + <span style-name="T25"> {{ + + input.PurposeDETemplate + + }} {</span> + </span> + <span style-name="ProxeusFormula">%</span> + <span style-name="ProxeusCode">endif</span> + <span style-name="ProxeusFormula">%}</span> + </p> +</list-item> \ No newline at end of file diff --git a/src/test/resources/input1_fixed.xml b/src/test/resources/input1_fixed.xml new file mode 100644 index 0000000..0324418 --- /dev/null +++ b/src/test/resources/input1_fixed.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<list-item> + <p style-name="P36"> + <span style-name="Fett"> + <span style-name="T25"></span></span>{% if input.PurposeDETemplate == ‘Other‘ %}<span style-name="ProxeusFormula"></span> + <span style-name="Fett"> + <span style-name="T25">{{ input.PurposeDE }} </span></span>{% else %}<span style-name="ProxeusFormula"></span> + <span style-name="Fett"> + <span style-name="T25"> {{ input.PurposeDETemplate }} </span></span>{% endif %}<span style-name="ProxeusFormula"></span> + </p> +</list-item> diff --git a/src/test/resources/manifest.xml b/src/test/resources/manifest.xml new file mode 100644 index 0000000..7a02b33 --- /dev/null +++ b/src/test/resources/manifest.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" manifest:version="1.2"> + <manifest:file-entry manifest:full-path="/" manifest:media-type="application/vnd.oasis.opendocument.text" manifest:version="1.2"></manifest:file-entry> + <manifest:file-entry manifest:full-path="styles.xml" manifest:media-type="text/xml"></manifest:file-entry> + <manifest:file-entry manifest:full-path="Pictures/10000000000000850000006377498356141931B6.jpg" manifest:media-type="image/jpeg"></manifest:file-entry> + <manifest:file-entry manifest:full-path="Thumbnails/thumbnail.png" manifest:media-type="image/png"></manifest:file-entry> + <manifest:file-entry manifest:full-path="Configurations2/" manifest:media-type="application/vnd.sun.xml.ui.configuration"></manifest:file-entry> + <manifest:file-entry manifest:full-path="content.xml" manifest:media-type="text/xml"></manifest:file-entry> + <manifest:file-entry manifest:full-path="meta.xml" manifest:media-type="text/xml"></manifest:file-entry> + <manifest:file-entry manifest:full-path="settings.xml" manifest:media-type="text/xml"></manifest:file-entry> + <manifest:file-entry manifest:full-path="manifest.rdf" manifest:media-type="application/rdf+xml"></manifest:file-entry> +</manifest:manifest> \ No newline at end of file diff --git a/src/test/resources/manifest_processed.xml b/src/test/resources/manifest_processed.xml new file mode 100644 index 0000000..51deecd --- /dev/null +++ b/src/test/resources/manifest_processed.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" manifest:version="1.2"> + <manifest:file-entry manifest:full-path="/" manifest:media-type="application/vnd.oasis.opendocument.text" manifest:version="1.2"></manifest:file-entry> + <manifest:file-entry manifest:full-path="styles.xml" manifest:media-type="text/xml"></manifest:file-entry> + + <manifest:file-entry manifest:full-path="Thumbnails/thumbnail.png" manifest:media-type="image/png"></manifest:file-entry> + <manifest:file-entry manifest:full-path="Configurations2/" manifest:media-type="application/vnd.sun.xml.ui.configuration"></manifest:file-entry> + <manifest:file-entry manifest:full-path="content.xml" manifest:media-type="text/xml"></manifest:file-entry> + <manifest:file-entry manifest:full-path="meta.xml" manifest:media-type="text/xml"></manifest:file-entry> + <manifest:file-entry manifest:full-path="settings.xml" manifest:media-type="text/xml"></manifest:file-entry> + <manifest:file-entry manifest:full-path="manifest.rdf" manifest:media-type="application/rdf+xml"></manifest:file-entry> +<manifest:file-entry manifest:full-path="foobar.jpg" manifest:media-type="image/png"></manifest:file-entry> +</manifest:manifest> diff --git a/src/test/resources/old/conf.json b/src/test/resources/old/conf.json new file mode 100644 index 0000000..fdecafb --- /dev/null +++ b/src/test/resources/old/conf.json @@ -0,0 +1,24 @@ +{ + "protocol":"http", + "host":"0.0.0.0", + "port":2115, + "tmpFolder":"docsCache",/** cache during a request, it will be deleted when the request is finished **/ + "min": 10,/** min workers **/ + "max": 100,/** max workers **/ + "timeout":"30s",/** timeout duration **/ + "logConfig":{ + "level":"INFO", /** OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL **/ + "level_console":"DEBUG", /** OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL **/ + "maxFileSize": "5MB", + "maxBackupIndex": 5, + "pattern": "%d{dd.MM.yyyy HH:mm:ss} %-5p %c{1}:%L - %m%n", + "filePath":"./logs/document-service.log" + }, + "libreConfig":{ + "librepath":"/Applications/LibreOffice.app/Contents/MacOS/soffice", /** the libreoffice executable folder path **/ + "min" : 10, /** default 8 | min executables ready to be ready. An executable is mainly needed to convert to PDF. It is recommended to use one exe for a request at the time.**/ + "max" : 100, /** default 40 | max capacity of executable running. The next request will be on hold until one is freed or until request timeout..**/ + "highLoad": 55 /** highLoad defines the percentage of executables in use, when it is reached prepare new ones to be ready for high availability and fast response.**/ + /** Please note! LibreOffice likes to fail sometimes, to have a stable failover, you might want to keep the highLoad value around 50% or even lower.**/ + } +} \ No newline at end of file diff --git a/src/test/resources/old/if_statement.xml b/src/test/resources/old/if_statement.xml new file mode 100644 index 0000000..c5818f5 --- /dev/null +++ b/src/test/resources/old/if_statement.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<list-item> + <p style-name="P36"> + <span style-name="Fett"> + <span style-name="T25">{</span> + </span> + <span style-name="ProxeusFormula">%</span> + <span style-name="ProxeusCode">if input.PurposeDETemplate == 'Other %}' </span> + <span style-name="ProxeusFormula">%}</span> + <span style-name="Fett"> + <span style-name="T25">{{</span> + </span> + <span style-name="ProxeusFormula">input.PurposeDE</span> + <span style-name="Fett"> + <span style-name="T25">}} {</span> + </span> + <span style-name="ProxeusFormula">%</span> + <span style-name="ProxeusCode">else</span> + <span style-name="ProxeusFormula">%}</span> + <span style-name="Fett"> + <span style-name="T25"> {{</span> + </span> + <span style-name="ProxeusFormula">input.PurposeDETemplate</span> + <span style-name="Fett"> + <span style-name="T25">}} {</span> + </span> + <span style-name="ProxeusFormula">%</span> + <span style-name="ProxeusCode">endif</span> + <span style-name="ProxeusFormula">%}</span> + </p> +</list-item> diff --git a/src/test/resources/old/if_statement_fixed.xml b/src/test/resources/old/if_statement_fixed.xml new file mode 100644 index 0000000..da919e4 --- /dev/null +++ b/src/test/resources/old/if_statement_fixed.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<list-item> + <p style-name="P36"> + <span style-name="Fett"> + <span style-name="T25">{</span> + </span> + <span style-name="ProxeusFormula">%</span> + <span style-name="ProxeusCode">if input.PurposeDETemplate == ‘Other‘ </span> + <span style-name="ProxeusFormula">%}</span> + <span style-name="Fett"> + <span style-name="T25">{{ + + input.PurposeDE + + }} {</span> + </span> + <span style-name="ProxeusFormula">%</span> + <span style-name="ProxeusCode">else</span> + <span style-name="ProxeusFormula">%}</span> + <span style-name="Fett"> + <span style-name="T25"> {{ + + input.PurposeDETemplate + + }} {</span> + </span> + <span style-name="ProxeusFormula">%</span> + <span style-name="ProxeusCode">endif</span> + <span style-name="ProxeusFormula">%}</span> + </p> +</list-item> diff --git a/src/test/resources/old/input1.xml b/src/test/resources/old/input1.xml new file mode 100644 index 0000000..767f284 --- /dev/null +++ b/src/test/resources/old/input1.xml @@ -0,0 +1,30 @@ +<list-item> + <p style-name="P36"> + <span style-name="Fett"> + <span style-name="T25">{</span> + </span> + <span style-name="ProxeusFormula">%</span> + <span style-name="ProxeusCode">if input.PurposeDETemplate == ‘Other‘ </span> + <span style-name="ProxeusFormula">%}</span> + <span style-name="Fett"> + <span style-name="T25">{{ + + input.PurposeDE + + }} {</span> + </span> + <span style-name="ProxeusFormula">%</span> + <span style-name="ProxeusCode">else</span> + <span style-name="ProxeusFormula">%}</span> + <span style-name="Fett"> + <span style-name="T25"> {{ + + input.PurposeDETemplate + + }} {</span> + </span> + <span style-name="ProxeusFormula">%</span> + <span style-name="ProxeusCode">endif</span> + <span style-name="ProxeusFormula">%}</span> + </p> +</list-item> \ No newline at end of file diff --git a/src/test/resources/old/input1_fixed.xml b/src/test/resources/old/input1_fixed.xml new file mode 100644 index 0000000..518c711 --- /dev/null +++ b/src/test/resources/old/input1_fixed.xml @@ -0,0 +1,17 @@ +<list-item> + <p style-name="P36"> + {% if input.PurposeDETemplate == ‘Other‘ %} + <span style-name="Fett"> + <span style-name="T25"> + {{ input.PurposeDE }} + </span> + </span> + { % else %} + <span style-name="Fett"> + <span style-name="T25"> + {{ input.PurposeDETemplate }} + </span> + </span> + {% endif %} + </p> +</list-item> diff --git a/src/test/resources/old/odt_body.xml b/src/test/resources/old/odt_body.xml new file mode 100644 index 0000000..f2f3079 --- /dev/null +++ b/src/test/resources/old/odt_body.xml @@ -0,0 +1,197 @@ +<?xml version="1.0" encoding="UTF-8"?> +<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2"> +<office:body> + <office:text> + <office:forms form:automatic-focus="false" form:apply-design-mode="false"/> + <text:sequence-decls> + <text:sequence-decl text:display-outline-level="0" text:name="Illustration"/> + <text:sequence-decl text:display-outline-level="0" text:name="Table"/> + <text:sequence-decl text:display-outline-level="0" text:name="Text"/> + <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/> + <text:sequence-decl text:display-outline-level="0" text:name="Figure"/> + </text:sequence-decls> + <text:p text:style-name="P5">Anmeldung an das Handelsregisteramt</text:p> + <text:p text:style-name="P4"/> + <text:list xml:id="list47114456" text:style-name="WWNum6"> + <text:list-item> + <text:p text:style-name="P35"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T7">Zur Eintragung in das Handelsregister wird folgende Neueintragung angemeldet:</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P38"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P38"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Firma</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:bookmark-start text:name="FirmaGerman"/> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.FirmaGerman</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T10">}}</text:span> + </text:span> + <text:bookmark-end text:name="FirmaGerman"/> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T10"> </text:span> + </text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">AG</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Übersetzungen der Firma</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.FirmaGerman</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}} SA</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.FirmaGerman</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}} Ltd</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Sitz</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.HeadquarterRegisteredOffice</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}} / {{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.HeadquarterCanton</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}}</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Domizil</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P14"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.HeadquarterZIP</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}} {{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.HeadquarterCity</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}}, {{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.HeadquarterStreet</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}} {{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.HeadquarterStreetNumber</text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">}} (eigenes Rechtsdomizil)</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Rechtsform</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7">Aktiengesellschaft</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Statutendatum</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:span text:style-name="Fett"> + <text:span text:style-name="T11">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.DateOfStatutes</text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T11">}}</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Zweck</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P36"> + <text:span text:style-name="Fett"> + <text:span text:style-name="T25">{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">%</text:span> + <text:span text:style-name="ProxeusCode">if input.PurposeDETemplate == ‘Other‘ </text:span> + <text:span text:style-name="ProxeusFormula">%}</text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T25">{{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.PurposeDE</text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T25">}} {</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">%</text:span> + <text:span text:style-name="ProxeusCode">else</text:span> + <text:span text:style-name="ProxeusFormula">%}</text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T25"> {{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">input.PurposeDETemplate</text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T25">}} {</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">%</text:span> + <text:span text:style-name="ProxeusCode">endif</text:span> + <text:span text:style-name="ProxeusFormula">%}</text:span> + </text:p> + </text:list-item> + </text:list> + <text:p text:style-name="P37"> + <text:span text:style-name="ProxeusFormula"/> + </text:p> + </office:text> + </office:body> +</office:document-content> diff --git a/src/test/resources/old/odt_body_fixed.xml b/src/test/resources/old/odt_body_fixed.xml new file mode 100644 index 0000000..99cc5e3 --- /dev/null +++ b/src/test/resources/old/odt_body_fixed.xml @@ -0,0 +1,197 @@ +<?xml version="1.0" encoding="UTF-8"?> +<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2"> +<office:body> + <office:text> + <office:forms form:automatic-focus="false" form:apply-design-mode="false"/> + <text:sequence-decls> + <text:sequence-decl text:display-outline-level="0" text:name="Illustration"/> + <text:sequence-decl text:display-outline-level="0" text:name="Table"/> + <text:sequence-decl text:display-outline-level="0" text:name="Text"/> + <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/> + <text:sequence-decl text:display-outline-level="0" text:name="Figure"/> + </text:sequence-decls> + <text:p text:style-name="P5">Anmeldung an das Handelsregisteramt</text:p> + <text:p text:style-name="P4"/> + <text:list xml:id="list47114456" text:style-name="WWNum6"> + <text:list-item> + <text:p text:style-name="P35"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T7">Zur Eintragung in das Handelsregister wird folgende Neueintragung angemeldet:</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P38"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P38"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Firma</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:bookmark-start text:name="FirmaGerman"/> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">{{ + + input.FirmaGerman + + }}</text:span> + </text:span> + <text:bookmark-end text:name="FirmaGerman"/> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T10"> </text:span> + </text:span> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">AG</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Übersetzungen der Firma</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">{{ + + input.FirmaGerman + + }} SA</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">{{ + + input.FirmaGerman + + }} Ltd</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Sitz</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">{{ + + input.HeadquarterRegisteredOffice + + }} / {{ + + input.HeadquarterCanton + + }}</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Domizil</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P14"> + <text:span text:style-name="Absatz-Standardschriftart"> + <text:span text:style-name="T8">{{ + + input.HeadquarterZIP + + }} {{ + + input.HeadquarterCity + + }}, {{ + + input.HeadquarterStreet + + }} {{ + + input.HeadquarterStreetNumber + + }} (eigenes Rechtsdomizil)</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Rechtsform</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7">Aktiengesellschaft</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Statutendatum</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P9"> + <text:span text:style-name="Fett"> + <text:span text:style-name="T11">{{ + + input.DateOfStatutes + + }}</text:span> + </text:span> + </text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P7"/> + </text:list-item> + <text:list-item> + <text:p text:style-name="P6">Zweck</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P36"> + <text:span text:style-name="Fett"> + <text:span text:style-name="T25">{</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">%</text:span> + <text:span text:style-name="ProxeusCode">if input.PurposeDETemplate == ‘Other‘ </text:span> + <text:span text:style-name="ProxeusFormula">%}</text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T25">{{ + + input.PurposeDE + + }} {</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">%</text:span> + <text:span text:style-name="ProxeusCode">else</text:span> + <text:span text:style-name="ProxeusFormula">%}</text:span> + <text:span text:style-name="Fett"> + <text:span text:style-name="T25"> {{ + + input.PurposeDETemplate + + }} {</text:span> + </text:span> + <text:span text:style-name="ProxeusFormula">%</text:span> + <text:span text:style-name="ProxeusCode">endif</text:span> + <text:span text:style-name="ProxeusFormula">%}</text:span> + </text:p> + </text:list-item> + </text:list> + <text:p text:style-name="P37"> + <text:span text:style-name="ProxeusFormula"/> + </text:p> + </office:text> + </office:body> +</office:document-content> diff --git a/src/test/resources/parse_test.xml b/src/test/resources/old/parse_test.xml similarity index 100% rename from src/test/resources/parse_test.xml rename to src/test/resources/old/parse_test.xml diff --git a/src/test/resources/old/simple.json b/src/test/resources/old/simple.json new file mode 100644 index 0000000..dacfe6d --- /dev/null +++ b/src/test/resources/old/simple.json @@ -0,0 +1,14 @@ +{ + "input":{ + "FirmaGerman":"testfirma", + "HeadquarterRegisteredOffice":"testoffice", + "HeadquarterCanton":"testcanton", + "HeadquarterZip":"testzip", + "HeadquarterCity":"testcity", + "HeadquarterStreet":"teststreet", + "HeadquarterStreetNumber":"testnumber", + "DateOfStatues":"testdos", + "PurposeDETemplate":"Other", + "PurposeDE":"testpurposede" + } +} diff --git a/src/test/resources/malformed_template_with_code.xml b/src/test/resources/old/template_with_code.xml similarity index 61% rename from src/test/resources/malformed_template_with_code.xml rename to src/test/resources/old/template_with_code.xml index 2a8adab..8f3b79b 100644 --- a/src/test/resources/malformed_template_with_code.xml +++ b/src/test/resources/old/template_with_code.xml @@ -1,31 +1,31 @@ <?xml version="1.0" encoding="UTF-8"?> <html> <body> - <ul:abc abc="1"> + <ul abc="1"> àààääää <a>{</a>% <b>set abc </b>= <c>"% } {{}}" %}</c> <a>{%</a> set abc2 = [] <a>%}</a> - <li:a abc="1"> + <li abc="1"> {%if (true)%} <span>before if{%if (false)%} after if</span> - </li:a> - <li:a abc="2"> + </li> + <li abc="2"> <span>before elseif{%elseif (false) %} after elseif</span> - </li:a> - <li:a abc="3"> + </li> + <li abc="3"> <span>before else{%else%} after else</span> <div>{%if input.IntendedDeliveryDate == ‘Specific Date‘ %}<p>{{input.SpecificDate}}{%else%}</p>{{input.DeliveryWeek}}<p>{%endif%}</p></div> - </li:a> - <li:a abc="4"> - <imgele name:var="{{input.myvar[abc:123]}}"></imgele> - <ul:abc abc="4.1"> - <li:a abc="4.1"> + </li> + <li abc="4"> + <imgele var="{{input.myvar[abc:123]}}"></imgele> + <ul abc="4.1"> + <li abc="4.1"> <span>lala{%endif%} omfg</span> - </li:a> - </ul:abc> + </li> + </ul> {%endif%} - </li:a> - </ul:abc> + </li> + </ul> </body> </html> diff --git a/src/test/resources/old/template_with_code2.xml b/src/test/resources/old/template_with_code2.xml new file mode 100644 index 0000000..8919c4c --- /dev/null +++ b/src/test/resources/old/template_with_code2.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<root> + <a><b>{</b><d></d></a><c>%</c> <b>set abc</b>=<c>"% } {{}}" %}</c> + <a><b>{</b><d></d></a><c>%</c> <b>if abc</b>==<c>"% } {{}}" %}</c> +</root> + diff --git a/src/test/resources/old/template_with_code2_fixed.xml b/src/test/resources/old/template_with_code2_fixed.xml new file mode 100644 index 0000000..8bbb801 --- /dev/null +++ b/src/test/resources/old/template_with_code2_fixed.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<root> + <a><b></b></a>{% set abc="% } {{}}" %}<c></c> + <a><b></b></a>{% if abc=="% } {{}}" %}<c></c> +</root> diff --git a/src/test/resources/fixed_template_with_code.xml b/src/test/resources/old/template_with_code_fixed.xml similarity index 54% rename from src/test/resources/fixed_template_with_code.xml rename to src/test/resources/old/template_with_code_fixed.xml index ae1a3c6..69f9e09 100644 --- a/src/test/resources/fixed_template_with_code.xml +++ b/src/test/resources/old/template_with_code_fixed.xml @@ -1,30 +1,30 @@ <?xml version="1.0" encoding="UTF-8"?> <html> <body> - <ul:abc abc="1"> + <ul abc="1"> àààääää {% set abc = "% } {{}}" %} <a>{% set abc2 = [] %}</a> - <li:a abc="1"> + <li abc="1"> {%if (true)%} <span>before if</span>{%if (false)%}<span> after if</span> - </li:a> - <li:a abc="2"> + </li> + <li abc="2"> <span>before elseif</span>{%elseif (false) %}<span> after elseif</span> - </li:a> - <li:a abc="3"> + </li> + <li abc="3"> <span>before else</span>{%else%}<span> after else</span> <div>{%if input.IntendedDeliveryDate == 'Specific Date' %}<p>{{input.SpecificDate}}</p>{%else%}{{input.DeliveryWeek}}<p></p>{%endif%}</div> - </li:a> - <li:a abc="4"> - <imgele name:var="img123"></imgele> - <ul:abc abc="4.1"> - <li:a abc="4.1"> - <span>lala</span></li:a></ul:abc>{%endif%}<ul:abc abc="4.1"><li:a abc="4.1"><span> omfg</span> - </li:a> - </ul:abc> + </li> + <li abc="4"> + <imgele var="img123"></imgele> + <ul abc="4.1"> + <li abc="4.1"> + <span>lala</span></li></ul>{%endif%}<ul abc="4.1"><li abc="4.1"><span> omfg</span> + </li> + </ul> {%endif%} - </li:a> - </ul:abc> + </li> + </ul> </body> </html> diff --git a/src/test/resources/simple.json b/src/test/resources/simple.json new file mode 100644 index 0000000..dacfe6d --- /dev/null +++ b/src/test/resources/simple.json @@ -0,0 +1,14 @@ +{ + "input":{ + "FirmaGerman":"testfirma", + "HeadquarterRegisteredOffice":"testoffice", + "HeadquarterCanton":"testcanton", + "HeadquarterZip":"testzip", + "HeadquarterCity":"testcity", + "HeadquarterStreet":"teststreet", + "HeadquarterStreetNumber":"testnumber", + "DateOfStatues":"testdos", + "PurposeDETemplate":"Other", + "PurposeDE":"testpurposede" + } +} diff --git a/src/test/resources/simple.odt b/src/test/resources/simple.odt new file mode 100644 index 0000000..0e5e328 Binary files /dev/null and b/src/test/resources/simple.odt differ diff --git a/src/test/resources/simple_noif_result.odt b/src/test/resources/simple_noif_result.odt new file mode 100644 index 0000000..5663bc9 Binary files /dev/null and b/src/test/resources/simple_noif_result.odt differ diff --git a/src/test/resources/simple_noif_template.odt b/src/test/resources/simple_noif_template.odt new file mode 100644 index 0000000..61a262d Binary files /dev/null and b/src/test/resources/simple_noif_template.odt differ diff --git a/src/test/resources/template_with_code.xml b/src/test/resources/template_with_code.xml new file mode 100644 index 0000000..8f3b79b --- /dev/null +++ b/src/test/resources/template_with_code.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<html> + <body> + <ul abc="1"> + àààääää + <a>{</a>% <b>set abc </b>= <c>"% } {{}}" %}</c> + <a>{%</a> set abc2 = [] <a>%}</a> + <li abc="1"> + {%if (true)%} + <span>before if{%if (false)%} after if</span> + </li> + <li abc="2"> + <span>before elseif{%elseif (false) %} after elseif</span> + </li> + <li abc="3"> + <span>before else{%else%} after else</span> + <div>{%if input.IntendedDeliveryDate == ‘Specific Date‘ %}<p>{{input.SpecificDate}}{%else%}</p>{{input.DeliveryWeek}}<p>{%endif%}</p></div> + </li> + <li abc="4"> + <imgele var="{{input.myvar[abc:123]}}"></imgele> + <ul abc="4.1"> + <li abc="4.1"> + <span>lala{%endif%} omfg</span> + </li> + </ul> + {%endif%} + </li> + </ul> + </body> +</html> + diff --git a/src/test/resources/template_with_code2.xml b/src/test/resources/template_with_code2.xml new file mode 100644 index 0000000..bb3acdc --- /dev/null +++ b/src/test/resources/template_with_code2.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<root> + <a><b>{</b><d></d></a><c>%</c> <b>set abc</b>=<c>"% } {{}}" %<a><b></b>}</a></c>{% endif %} + <a><b>{</b><d></d></a><c>%</c> <b>if abc</b>==<c>"% } {{}}" %<a><b></b>}</a></c>{% endif %} +</root> + diff --git a/src/test/resources/template_with_code2_fixed.xml b/src/test/resources/template_with_code2_fixed.xml new file mode 100644 index 0000000..80890c4 --- /dev/null +++ b/src/test/resources/template_with_code2_fixed.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<root> + <a><b></b></a>{% set abc="% } {{}}" %}<c><a></a></c>{% endif %} + <a><b></b></a>{% if abc=="% } {{}}" %}<c><a></a></c>{% endif %} +</root> diff --git a/src/test/resources/template_with_code_fixed.xml b/src/test/resources/template_with_code_fixed.xml new file mode 100644 index 0000000..69f9e09 --- /dev/null +++ b/src/test/resources/template_with_code_fixed.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<html> + <body> + <ul abc="1"> + àààääää + {% set abc = "% } {{}}" %} + <a>{% set abc2 = [] %}</a> + <li abc="1"> + {%if (true)%} + <span>before if</span>{%if (false)%}<span> after if</span> + </li> + <li abc="2"> + <span>before elseif</span>{%elseif (false) %}<span> after elseif</span> + </li> + <li abc="3"> + <span>before else</span>{%else%}<span> after else</span> + <div>{%if input.IntendedDeliveryDate == 'Specific Date' %}<p>{{input.SpecificDate}}</p>{%else%}{{input.DeliveryWeek}}<p></p>{%endif%}</div> + </li> + <li abc="4"> + <imgele var="img123"></imgele> + <ul abc="4.1"> + <li abc="4.1"> + <span>lala</span></li></ul>{%endif%}<ul abc="4.1"><li abc="4.1"><span> omfg</span> + </li> + </ul> + {%endif%} + </li> + </ul> + </body> +</html> diff --git a/src/test/resources/xml_element_spanning_template_blocks.xml b/src/test/resources/xml_element_spanning_template_blocks.xml new file mode 100644 index 0000000..b0ac6fe --- /dev/null +++ b/src/test/resources/xml_element_spanning_template_blocks.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<doc> + <a> + <f> + first line + {% if foobar %} + second line + <b><e> + third line + {<d>% elseif barfoo %} + <c> + fourth line + {{ barfoo + foobar }} + </c> + {% elseif foofoo %} + {# comment</d> #} + </e> + </b> + fifth line + {% endif %} + + sixth line + {% if barbar %} + seventh line + </f> + {% endif %} + </a> +</doc> \ No newline at end of file diff --git a/src/test/resources/xml_element_spanning_template_blocks_fixed.xml b/src/test/resources/xml_element_spanning_template_blocks_fixed.xml new file mode 100644 index 0000000..7fe1887 --- /dev/null +++ b/src/test/resources/xml_element_spanning_template_blocks_fixed.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<doc> + <a> + <f> + first line + {% if foobar %} + second line + <b><e> + third line + </e></b>{% elseif barfoo %}<b><e><d> + <c> + fourth line + {{ barfoo + foobar }} + </c> + </d></e></b>{% elseif foofoo %}<b><e><d> + </d>{# comment #} + </e> + </b> + fifth line + {% endif %} + + sixth line + </f>{% if barbar %}<f> + seventh line + </f> + {% endif %} + </a> +</doc> \ No newline at end of file diff --git a/src/test/resources/xml_tags_in_island.xml b/src/test/resources/xml_tags_in_island.xml new file mode 100644 index 0000000..3e2975c --- /dev/null +++ b/src/test/resources/xml_tags_in_island.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<doc> + first line + <a> + second line + </a> + <b> + third line + {% if + </b> + <d> + foobar</d> <e><c> barfoo %} + fourth line</c> + fifth line {% endif </e> %} +</doc> \ No newline at end of file diff --git a/src/test/resources/xml_tags_in_island_fixed.xml b/src/test/resources/xml_tags_in_island_fixed.xml new file mode 100644 index 0000000..8dea3c1 --- /dev/null +++ b/src/test/resources/xml_tags_in_island_fixed.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<doc> + first line + <a> + second line + </a> + <b> + third line + </b>{% if foobar barfoo %}<e><c> + fourth line</c> + fifth line </e>{% endif %} +</doc> \ No newline at end of file diff --git a/test.odt b/test.odt new file mode 100644 index 0000000..49a7acd Binary files /dev/null and b/test.odt differ diff --git a/ui_service b/ui_service old mode 100644 new mode 100755