Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ e.g. 4.2.9, `FundsXML_Files/4.2.9/positions/Mixed-Fund_Positions.xml`
(or attach/inline a minimal FundsXML snippet — no real/PII data).

**What I ran**
The exact command(s), including any `tools/fetch-schema.sh` /
`tools/fetch-tools.sh` step.
The exact command(s), including the `./mvnw` (or `mvnw.cmd`) invocation for
Java examples, or any `tools/fetch-schema.sh` step.

**Expected vs. actual**
What you expected and what happened (paste the full error / output).
Expand Down
97 changes: 58 additions & 39 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,27 +67,50 @@ jobs:
fi
echo "xsd-invalid correctly rejected"

- name: Fetch Java toolchain (Saxon + SchXslt)
run: tools/fetch-tools.sh
# ---------------------------------------------------------------------
# Java examples — built & run via the committed Maven Wrapper. The first
# ./mvnw bootstraps Maven itself, then resolves all deps from Central.
# A repo-wide `compile` builds every module once so later `exec:java`
# steps need no `compile` goal (keeps stdout clean for the XQuery step,
# which serializes its result to stdout).
# ---------------------------------------------------------------------
- name: Java - build all modules (Maven Wrapper)
run: ./mvnw -q -B compile

- name: Java - XSD validation (in-language schema resolve)
run: |
set -e
M="./mvnw -q -B -pl XSD_Validation/java exec:java"
# Cache is warm from the xmllint step: exercises the resolver's
# cache-hit path and the $FUNDSXML_SCHEMA_DIR env override.
$M -Dexec.args="4.2.9 FundsXML_Files/4.2.9/positions/Mixed-Fund_Positions.xml"
FUNDSXML_SCHEMA_DIR="$PWD/.schema-cache/4.1.0" \
$M -Dexec.args="4.1.0 FundsXML_Files/4.1.0/positions/Equity-Fund_Positions.xml"
if $M -Dexec.args="4.2.9 tests/fixtures/invalid/xsd-invalid_Positions.xml"; then
echo "::error::xsd-invalid unexpectedly validated (Java)"; exit 1
fi
echo "Java XsdValidate: positive ok, negative correctly rejected"

- name: Schematron - canonical sample passes, fixture fails
run: |
RS=Schematron_DataQuality_Checks/Basic_Checks/invocation/run-schematron.sh
"$RS" FundsXML_Files/4.2.9/positions/Mixed-Fund_Positions.xml
if "$RS" tests/fixtures/invalid/schematron-invalid_Positions.xml; then
set -e
SCH=Schematron_DataQuality_Checks/Basic_Checks/basic_checks.sch
M="./mvnw -q -B -pl Schematron_DataQuality_Checks/Basic_Checks/invocation exec:java"
$M -Dexec.args="$SCH FundsXML_Files/4.2.9/positions/Mixed-Fund_Positions.xml"
if $M -Dexec.args="$SCH tests/fixtures/invalid/schematron-invalid_Positions.xml"; then
echo "::error::schematron-invalid fixture unexpectedly passed"; exit 1
fi
echo "schematron-invalid correctly failed"

- name: Smoke - XSLT transforms produce non-empty output
run: |
set -e
RT=XSLT_Transformations/invocation/run-transform.sh
M="./mvnw -q -B -pl XSLT_Transformations/invocation exec:java"
SRC=FundsXML_Files/4.2.9/positions/Mixed-Fund_Positions.xml
"$RT" XSLT_DataQuality_Checks/Custom_Internal_Checks/custom_internal_checks.xslt "$SRC" out_dq.html
"$RT" XSLT_Transformations/Factsheet/factsheet_html.xslt "$SRC" out_fs.html
"$RT" XSLT_Transformations/Factsheet/factsheet_fo.xslt "$SRC" out_fs.fo
"$RT" XSLT_Transformations/CSV_Export/positions_csv.xslt "$SRC" out_pos.csv
$M -Dexec.args="XSLT_DataQuality_Checks/Custom_Internal_Checks/custom_internal_checks.xslt $SRC out_dq.html"
$M -Dexec.args="XSLT_Transformations/Factsheet/factsheet_html.xslt $SRC out_fs.html"
$M -Dexec.args="XSLT_Transformations/Factsheet/factsheet_fo.xslt $SRC out_fs.fo"
$M -Dexec.args="XSLT_Transformations/CSV_Export/positions_csv.xslt $SRC out_pos.csv"
xmllint --noout out_fs.fo
for f in out_dq.html out_fs.html out_pos.csv; do
test -s "$f" || { echo "::error::$f is empty"; exit 1; }
Expand All @@ -97,12 +120,14 @@ jobs:
- name: Smoke - XQuery examples run and produce XML
run: |
set -e
RQ=XQuery_Examples/invocation/run-xquery.sh
M="./mvnw -q -B -pl XQuery_Examples/invocation exec:java"
SRC=FundsXML_Files/4.2.9/positions/Mixed-Fund_Positions.xml
"$RQ" XQuery_Examples/aggregate-by-assettype.xq "$SRC" out_agg.xml
"$RQ" XQuery_Examples/top-holdings.xq "$SRC" out_top.xml n=5
"$RQ" XQuery_Examples/fund-summary.xq "$SRC" out_sum.xml
"$RQ" XQuery_Examples/look-through.xq "$SRC" out_lt.xml
# RunXQuery serializes to stdout; -q keeps Maven silent so the
# redirect captures pure XML.
$M -Dexec.args="XQuery_Examples/aggregate-by-assettype.xq $SRC" > out_agg.xml
$M -Dexec.args="XQuery_Examples/top-holdings.xq $SRC n=5" > out_top.xml
$M -Dexec.args="XQuery_Examples/fund-summary.xq $SRC" > out_sum.xml
$M -Dexec.args="XQuery_Examples/look-through.xq $SRC" > out_lt.xml
for f in out_agg.xml out_top.xml out_sum.xml out_lt.xml; do
xmllint --noout "$f"
done
Expand All @@ -111,19 +136,18 @@ jobs:
- name: XML signature - Apache Santuario sign/verify/tamper roundtrip
run: |
set -e
XML_Signature/generate-test-key.sh
CP=.lib/xmlsec-4.0.4.jar:.lib/commons-codec-1.18.0.jar:.lib/slf4j-api-2.0.17.jar:.lib/slf4j-nop-2.0.17.jar
javac -cp "$CP" -d /tmp/sig \
XML_Signature/java/SignFundsXml.java XML_Signature/java/VerifyFundsXml.java
M="./mvnw -q -B -pl XML_Signature/java exec:java"
SRC=FundsXML_Files/4.2.9/positions/Mixed-Fund_Positions.xml
java -cp "$CP:/tmp/sig" SignFundsXml "$SRC" signed.xml \
XML_Signature/keys/test-signing.p12 changeit fundsxml
java -cp "$CP:/tmp/sig" VerifyFundsXml signed.xml \
XML_Signature/keys/test-signing-cert.pem
# In-language key generation (JDK keytool, no openssl).
$M -Dexec.mainClass=GenerateTestKey
$M -Dexec.mainClass=SignFundsXml \
-Dexec.args="$SRC signed.xml XML_Signature/keys/test-signing.p12 changeit fundsxml"
$M -Dexec.mainClass=VerifyFundsXml \
-Dexec.args="signed.xml XML_Signature/keys/test-signing-cert.pem"
xmllint --noout --nonet --schema .schema-cache/4.2.9/FundsXML.xsd signed.xml
sed 's/<TotalPercentage>8.33</<TotalPercentage>9.33</' signed.xml > tampered.xml
if java -cp "$CP:/tmp/sig" VerifyFundsXml tampered.xml \
XML_Signature/keys/test-signing-cert.pem; then
if $M -Dexec.mainClass=VerifyFundsXml \
-Dexec.args="tampered.xml XML_Signature/keys/test-signing-cert.pem"; then
echo "::error::tampered file unexpectedly verified"; exit 1
fi
echo "tamper correctly detected"
Expand All @@ -132,7 +156,6 @@ jobs:
run: |
set -e
python3 -m pip install --quiet lxml
tools/fetch-tools.sh # sqlite-jdbc -> .lib/
FX=FundsXML_Files/4.2.9/positions/Multi-Fund_Positions.xml
MX=FundsXML_Files/4.2.9/positions/Mixed-Fund_Positions.xml
DOC=FUNDSXML_MULTI_1
Expand All @@ -151,15 +174,10 @@ jobs:
xmllint --noout --nonet --schema "$XSD" py.xml
$EQ "$FX" py.xml

# Java (sqlite-jdbc)
CP=.lib/sqlite-jdbc-3.46.1.3.jar
javac -cp "$CP" -d /tmp/jdb \
Database_Integration/java/ImportFundsXml.java \
Database_Integration/java/ExportFundsXml.java
java --enable-native-access=ALL-UNNAMED -cp "$CP:/tmp/jdb" \
ImportFundsXml java.db "$FX"
java --enable-native-access=ALL-UNNAMED -cp "$CP:/tmp/jdb" \
ExportFundsXml java.db "$DOC" java.xml
# Java (sqlite-jdbc via Maven; classes already built above)
MJ="./mvnw -q -B -pl Database_Integration/java exec:java"
$MJ -Dexec.mainClass=ImportFundsXml -Dexec.args="java.db $FX"
$MJ -Dexec.mainClass=ExportFundsXml -Dexec.args="java.db $DOC java.xml"
xmllint --noout --nonet --schema "$XSD" java.xml
$EQ "$FX" java.xml

Expand Down Expand Up @@ -195,8 +213,10 @@ jobs:
python3 $P/stream_aggregate.py big.xml | tee agg.txt
grep -q '^positions : 30000$' agg.txt
grep -q '^sum value (EUR): 30000000.00$' agg.txt
javac -d /tmp/lf Large_File_Processing/java/StreamAggregate.java
java -Xmx64m -cp /tmp/lf StreamAggregate big.xml | tee aggj.txt
# Java StreamAggregate (pure JDK) under a small heap proves the
# constant-memory claim; MAVEN_OPTS bounds the in-process JVM.
MAVEN_OPTS=-Xmx64m ./mvnw -q -B -pl Large_File_Processing/java exec:java \
-Dexec.args="big.xml" | tee aggj.txt
grep -q '^positions : 30000$' aggj.txt
python3 $P/split.py big.xml chunks/ 10000
test "$(ls chunks/chunk-*.xml | wc -l)" = "3"
Expand Down Expand Up @@ -224,8 +244,7 @@ jobs:
assert npos(o) == npos(r), (npos(o), npos(r))
print("JSON round-trip preserved:", nav(r), npos(r))
PY
javac -d /tmp/nb Data_Binding_JSON/java/NativeBinding.java
java -cp /tmp/nb NativeBinding "$SRC" | tee nb.txt
./mvnw -q -B -pl Data_Binding_JSON/java exec:java -Dexec.args="$SRC" | tee nb.txt
grep -q '^Positions : 21$' nb.txt

- name: Regression - legacy XSLT 1.0 report still runs
Expand Down
15 changes: 11 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ CLAUDE.md
.DS_Store
._*

# Locally fetched XSD releases (via tools/fetch-schema.sh) — not committed,
# the source of truth is the official GitHub release.
# Locally cached XSD releases — not committed, the source of truth is the
# official GitHub release. Each example downloads + caches it here itself
# (honouring $FUNDSXML_SCHEMA_DIR); see XSD_Validation/java/XsdValidate.java.
.schema-cache/

# Locally fetched Java toolchain jars (via tools/fetch-tools.sh) — external
# dependencies from Maven Central, not repo source.
# Maven build output. Dependencies come from Maven Central via ./mvnw; the
# committed Maven Wrapper bootstraps Maven itself — nothing is vendored.
target/
# Legacy: jars the since-removed tools/fetch-tools.sh used to download here.
.lib/

# Throwaway signing keys (XML_Signature/generate-test-key.sh) — never commit
Expand Down Expand Up @@ -38,6 +41,10 @@ fund.json
*.db
*.svrl

# Python bytecode cache
__pycache__/
*.pyc

# Node example deps (Database_Integration/javascript) — restored via npm install
node_modules/
package-lock.json
Expand Down
19 changes: 19 additions & 0 deletions .mvn/wrapper/maven-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
wrapperVersion=3.3.2
distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
16 changes: 13 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,22 @@ Please read this before opening a pull request.

Run what you changed and confirm it actually works — no "should pass" claims.

The Java examples build standalone via the committed Maven Wrapper (`./mvnw`,
or `mvnw.cmd` on Windows) — dependencies come from Maven Central, there is no
`fetch-tools.sh` and no `.lib/`.

```bash
tools/fetch-schema.sh 4.2.9 # XSD cache (gitignored)
tools/fetch-tools.sh # Saxon / SchXslt / sqlite-jdbc / Santuario
tools/fetch-schema.sh 4.2.9 # XSD cache for the xmllint/Python steps
# (the Java examples also resolve the
# XSD themselves; see XsdValidate)

xmllint --noout --schema .schema-cache/4.2.9/FundsXML.xsd <your-sample>.xml
Schematron_DataQuality_Checks/Basic_Checks/invocation/run-schematron.sh <sample>.xml

# Schematron via the Maven Wrapper (positive sample -> exit 0)
./mvnw -q -pl Schematron_DataQuality_Checks/Basic_Checks/invocation \
compile exec:java \
-Dexec.args="Schematron_DataQuality_Checks/Basic_Checks/basic_checks.sch <sample>.xml"

# DB round-trip example:
python3 Database_Integration/python/import_fundsxml.py fx.db <sample>.xml
python3 Database_Integration/python/export_fundsxml.py fx.db <docId> out.xml
Expand Down
5 changes: 3 additions & 2 deletions Data_Binding_JSON/java/NativeBinding.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// Native Java data binding for FundsXML — DOM + XPath into records, NO JAXB.
//
// javac -d /tmp/nb Data_Binding_JSON/java/NativeBinding.java
// java -cp /tmp/nb NativeBinding <fundsxml.xml>
// Standalone & cross-platform — run from the repo root with the Maven Wrapper:
// ./mvnw -q -pl Data_Binding_JSON/java compile exec:java \
// -Dexec.args="<fundsxml.xml>"
//
// Why no JAXB: the FundsXML schema is huge; generating/maintaining a full JAXB
// model is heavy and brittle across versions. For most integration work a thin
Expand Down
29 changes: 29 additions & 0 deletions Data_Binding_JSON/java/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Native Java data binding for FundsXML (DOM + XPath into records, no JAXB).
Pure JDK, no third-party dependencies.

Run from the repo root:
./mvnw -q -pl Data_Binding_JSON/java compile exec:java \
-Dexec.args="FundsXML_Files/4.2.9/positions/Mixed-Fund_Positions.xml"
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.fundsxml.examples</groupId>
<artifactId>fundsxml-examples</artifactId>
<version>1.0.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<artifactId>data-binding-java</artifactId>
<properties>
<exec.mainClass>NativeBinding</exec.mainClass>
</properties>

<build>
<sourceDirectory>${project.basedir}</sourceDirectory>
</build>
</project>
13 changes: 5 additions & 8 deletions Database_Integration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,11 @@ DOC=FUNDSXML_MULTI_1
python3 Database_Integration/python/import_fundsxml.py fx.db "$FX"
python3 Database_Integration/python/export_fundsxml.py fx.db "$DOC" out.xml

# Java (sqlite-jdbc fetched into .lib/ by tools/fetch-tools.sh)
tools/fetch-tools.sh
CP=.lib/sqlite-jdbc-3.46.1.3.jar
javac -cp "$CP" -d /tmp/db \
Database_Integration/java/ImportFundsXml.java \
Database_Integration/java/ExportFundsXml.java
java --enable-native-access=ALL-UNNAMED -cp "$CP:/tmp/db" ImportFundsXml fx.db "$FX"
java --enable-native-access=ALL-UNNAMED -cp "$CP:/tmp/db" ExportFundsXml fx.db "$DOC" out.xml
# Java (sqlite-jdbc from Maven Central via the committed Maven Wrapper;
# on Windows use mvnw.cmd)
MJ="./mvnw -q -pl Database_Integration/java compile exec:java"
$MJ -Dexec.mainClass=ImportFundsXml -Dexec.args="fx.db $FX"
$MJ -Dexec.mainClass=ExportFundsXml -Dexec.args="fx.db $DOC out.xml"

# JavaScript
( cd Database_Integration/javascript && npm install )
Expand Down
11 changes: 5 additions & 6 deletions Database_Integration/java/ExportFundsXml.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@
//
// DB SCHEMA ../ddl/schema.sql (already populated by ImportFundsXml).
//
// RUN
// CP=.lib/sqlite-jdbc-3.46.1.3.jar
// javac -cp "$CP" -d /tmp/db Database_Integration/java/ExportFundsXml.java
// java --enable-native-access=ALL-UNNAMED -cp "$CP:/tmp/db" \
// ExportFundsXml fx.db FUNDSXML_MULTI_1 out.xml
// RUN Standalone & cross-platform, from the repo root via the Maven Wrapper:
// ./mvnw -q -pl Database_Integration/java compile exec:java \
// -Dexec.mainClass=ExportFundsXml -Dexec.args="fx.db FUNDSXML_MULTI_1 out.xml"
//
// DEPENDENCIES org.xerial:sqlite-jdbc + the JDK (native javax.xml, no JAXB).
// DEPENDENCIES org.xerial:sqlite-jdbc (Maven Central, see pom.xml) + the JDK
// (native javax.xml, no JAXB).
//
// FUNDSXML NOTES
// * No XML namespace -> plain element names.
Expand Down
13 changes: 6 additions & 7 deletions Database_Integration/java/ImportFundsXml.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@
// share_class per fund; asset document-scoped). Creates the schema in a
// fresh SQLite DB, then loads the file.
//
// RUN (sqlite-jdbc fetched by tools/fetch-tools.sh into .lib/)
// tools/fetch-tools.sh
// CP=.lib/sqlite-jdbc-3.46.1.3.jar
// javac -cp "$CP" -d /tmp/db Database_Integration/java/ImportFundsXml.java
// java --enable-native-access=ALL-UNNAMED -cp "$CP:/tmp/db" \
// ImportFundsXml fx.db FundsXML_Files/4.2.9/positions/Multi-Fund_Positions.xml
// RUN Standalone & cross-platform, from the repo root via the Maven Wrapper:
// ./mvnw -q -pl Database_Integration/java compile exec:java \
// -Dexec.mainClass=ImportFundsXml \
// -Dexec.args="fx.db FundsXML_Files/4.2.9/positions/Multi-Fund_Positions.xml"
//
// DEPENDENCIES org.xerial:sqlite-jdbc + the JDK. XML via native javax.xml
// DEPENDENCIES org.xerial:sqlite-jdbc (Maven Central, see pom.xml) + the JDK.
// XML via native javax.xml
// DOM/XPath — NO JAXB (a thin DOM binding is smaller and version-tolerant).
//
// FUNDSXML ASSUMPTIONS
Expand Down
Loading