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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ 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
# Throwaway signing keys (XML_Signature/java/GenerateTestKey.java) — never commit
# private keys, even demo ones.
XML_Signature/keys/

Expand Down
3 changes: 2 additions & 1 deletion Data_Binding_JSON/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ Two recurring enterprise needs: exposing FundsXML to **JSON** APIs, and

[`python/fundsxml_json.py`](python/fundsxml_json.py) — `to-json` / `from-json`
/ `roundtrip` (stdlib + lxml). Stable JSON shape
(`document` / `fund` / `shareClasses` / `positions` / `assets`); `from-json`
(`document` / `funds[]` / per fund `shareClasses[]` + `portfolios[]/positions[]` /
`assets[]`); `from-json`
produces **XSD-valid** FundsXML 4.2.9. Lossless for the positions core,
intentionally lossy for issuer / derivative / regulatory detail (same scope
boundary as `Database_Integration/`).
Expand Down
16 changes: 10 additions & 6 deletions Data_Binding_JSON/java/NativeBinding.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,23 @@ public static void main(String[] args) throws Exception {
}
XPath xp = XPathFactory.newInstance().newXPath();

String ccy = xp.evaluate("/FundsXML4/Funds/Fund/Currency", doc);
// Single-fund binding on purpose: this example binds the FIRST Fund
// (metadata and positions alike). For a multi-fund document use the
// Python fundsxml_json.py, which projects funds[] as a list.
String f = "/FundsXML4/Funds/Fund[1]";
String ccy = xp.evaluate(f + "/Currency", doc);
Fund fund = new Fund(
xp.evaluate("/FundsXML4/Funds/Fund/Identifiers/LEI", doc),
xp.evaluate("/FundsXML4/Funds/Fund/Names/OfficialName", doc),
xp.evaluate(f + "/Identifiers/LEI", doc),
xp.evaluate(f + "/Names/OfficialName", doc),
ccy,
Double.parseDouble(xp.evaluate(
"/FundsXML4/Funds/Fund/FundDynamicData/TotalAssetValues/"
f + "/FundDynamicData/TotalAssetValues/"
+ "TotalAssetValue/TotalNetAssetValue/Amount[@ccy='" + ccy
+ "']", doc)),
((Number) xp.evaluate(
"count(//Position)", doc, XPathConstants.NUMBER)).intValue());
"count(" + f + "//Position)", doc, XPathConstants.NUMBER)).intValue());

NodeList pn = (NodeList) xp.evaluate("//Positions/Position", doc,
NodeList pn = (NodeList) xp.evaluate(f + "//Positions/Position", doc,
XPathConstants.NODESET);
List<Position> positions = new ArrayList<>();
double sumPct = 0;
Expand Down
3 changes: 2 additions & 1 deletion Data_Binding_JSON/python/fundsxml_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,8 @@ def from_json(data: dict, out_path: str) -> None:
def main() -> int:
a = sys.argv[1:]
if len(a) != 3:
print(__doc__, file=sys.stderr)
print("usage: fundsxml_json.py to-json|from-json|roundtrip <src> <dst>",
file=sys.stderr)
return 2
mode, src, dst = a
if mode == "to-json":
Expand Down
8 changes: 5 additions & 3 deletions Database_Integration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ FundsXML — so you can lift exactly the direction you need:

| Language | Import (FundsXML → DB) | Export (DB → FundsXML) | DB driver | Verified |
|----------|------------------------|------------------------|-----------|----------|
| Python | [`python/import_fundsxml.py`](python/import_fundsxml.py) | [`python/export_fundsxml.py`](python/export_fundsxml.py) | stdlib `sqlite3` | ✅ locally |
| Java | [`java/ImportFundsXml.java`](java/ImportFundsXml.java) | [`java/ExportFundsXml.java`](java/ExportFundsXml.java) | `sqlite-jdbc` (native `javax.xml`, no JAXB) | ✅ locally |
| JavaScript | [`javascript/import_fundsxml.mjs`](javascript/import_fundsxml.mjs) | [`javascript/export_fundsxml.mjs`](javascript/export_fundsxml.mjs) | `sql.js` (pure-WASM) | ✅ locally |
| Python | [`python/import_fundsxml.py`](python/import_fundsxml.py) | [`python/export_fundsxml.py`](python/export_fundsxml.py) | stdlib `sqlite3` | ✅ locally + CI |
| Java | [`java/ImportFundsXml.java`](java/ImportFundsXml.java) | [`java/ExportFundsXml.java`](java/ExportFundsXml.java) | `sqlite-jdbc` (native `javax.xml`, no JAXB) | ✅ locally + CI |
| JavaScript | [`javascript/import_fundsxml.mjs`](javascript/import_fundsxml.mjs) | [`javascript/export_fundsxml.mjs`](javascript/export_fundsxml.mjs) | `sql.js` (pure-WASM) | ✅ locally + CI |
| C# / .NET | [`csharp/import/`](csharp/import/) | [`csharp/export/`](csharp/export/) | `Microsoft.Data.Sqlite` | ✅ locally + CI |

Every program is **self-contained** (one file / one project, its own copy of
Expand Down Expand Up @@ -63,6 +63,8 @@ FX=FundsXML_Files/4.2.9/positions/Multi-Fund_Positions.xml
DOC=FUNDSXML_MULTI_1

# Python
# Python needs lxml: create the venv from the repo's pyproject.toml once
# (python -m venv .venv && . .venv/bin/activate && pip install -e .)
python3 Database_Integration/python/import_fundsxml.py fx.db "$FX"
python3 Database_Integration/python/export_fundsxml.py fx.db "$DOC" out.xml

Expand Down
5 changes: 3 additions & 2 deletions Database_Integration/csharp/export/ExportFundsXml.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Standalone console app: exports SQLite rows back to a FundsXML file.
Run (see ExportFundsXml.cs header for arguments):
dotnet run project Database_Integration/csharp/export fx.db id out.xml -->
Run with "dotnet run" and the project switch pointing at this
directory, then the arguments fx.db id out.xml; the exact command line
is in the ExportFundsXml.cs header (XML comments cannot contain a double dash). -->
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
Expand Down
5 changes: 3 additions & 2 deletions Database_Integration/csharp/import/ImportFundsXml.csproj
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Standalone console app: imports a FundsXML file into SQLite.
Microsoft.Data.Sqlite bundles native SQLite (no system install).
Run (see ImportFundsXml.cs header for arguments):
dotnet run project Database_Integration/csharp/import fx.db file.xml -->
Run with "dotnet run" and the project switch pointing at this
directory, then the arguments fx.db file.xml; the exact command line is
in the ImportFundsXml.cs header (XML comments cannot contain a double dash). -->
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
Expand Down
8 changes: 6 additions & 2 deletions Database_Integration/java/ExportFundsXml.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,12 @@ public static void main(String[] args) throws Exception {
doc.appendChild(root);

try (Connection c = DriverManager.getConnection("jdbc:sqlite:" + db)) {
ResultSet d = c.createStatement().executeQuery(
"SELECT * FROM document WHERE document_id='" + docId + "'");
// Bind the id (never concatenate user input into SQL) — the same
// rule every other query in this file follows.
PreparedStatement dq = c.prepareStatement(
"SELECT * FROM document WHERE document_id = ?");
dq.setString(1, docId);
ResultSet d = dq.executeQuery();
if (!d.next()) throw new RuntimeException("no document " + docId);

Element cd = el(doc, root, "ControlData", null);
Expand Down
2 changes: 1 addition & 1 deletion Database_Integration/javascript/export_fundsxml.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// RUN
// node import_fundsxml.mjs fx.db some.xml
// node export_fundsxml.mjs fx.db FUNDSXML_MULTI_1 out.xml
// node ../tools/xml_equiv.py # (python) prove some.xml == out.xml
// python3 ../tools/xml_equiv.py some.xml out.xml # (needs lxml, see pyproject.toml) prove some.xml == out.xml
//
// DEPENDENCIES sql.js (WASM SQLite) + @xmldom/xmldom (DOM serialization).
//
Expand Down
5 changes: 3 additions & 2 deletions Database_Integration/javascript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
"private": true,
"type": "module",
"description": "Standalone FundsXML <-> SQLite round-trip example (Node.js).",
"//": "Pure-JS deps so it runs anywhere with no native build: sql.js is SQLite compiled to WebAssembly; @xmldom/xmldom + xpath give a namespace-free DOM. Run: npm install && node fundsxml_db.mjs roundtrip <in.xml> <out.xml>",
"//": "Pure-JS deps so it runs anywhere with no native build: sql.js is SQLite compiled to WebAssembly; @xmldom/xmldom + xpath give a namespace-free DOM. Run: npm install && node import_fundsxml.mjs fx.db <in.xml> && node export_fundsxml.mjs fx.db <document-id> <out.xml>",
"scripts": {
"roundtrip": "node fundsxml_db.mjs roundtrip"
"import": "node import_fundsxml.mjs",
"export": "node export_fundsxml.mjs"
},
"dependencies": {
"@xmldom/xmldom": "^0.9.8",
Expand Down
6 changes: 3 additions & 3 deletions FundsXML_Files/4.2.9/positions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ This directory contains a comprehensive FundsXML sample document demonstrating a
### Portfolio Summary

- **Total Positions**: 21
- **Asset Types**: 13 different types
- **Asset Types**: 12 different types
- **Currencies**: EUR, USD

## Asset Types Demonstrated
Expand All @@ -72,7 +72,7 @@ This sample file includes examples of all major FundsXML asset types:

| ID | ISIN | Name | Type | Value (EUR) | % |
|----|------|------|------|-------------|---|
| ID_001 | US0378331005 | Apple Inc. | EQ | 9,375,000 | 7.50% |
| ID_001 | US0378331005 | Apple Inc. | EQ | 9,375,000 | 8.33% |
| ID_002 | NL0010273215 | ASML Holding N.V. | EQ | 8,125,000 | 6.50% |
| ID_003 | DE0001102424 | Germany 1.70% 2032 | BO | 6,250,000 | 5.00% |
| ID_004 | XS2444622110 | Siemens 0.75% 2030 | BO | 6,250,000 | 5.00% |
Expand Down Expand Up @@ -145,7 +145,7 @@ illustrative; the XML file is authoritative (see Reconciliation note).
<TotalValue>
<Amount ccy="EUR">9375000</Amount>
</TotalValue>
<TotalPercentage>7.50</TotalPercentage>
<TotalPercentage>8.33</TotalPercentage>
<Equity>
<Units>50000.00</Units>
<Price>
Expand Down
2 changes: 1 addition & 1 deletion FundsXML_Files/4.2.9/regulatory/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

## Contents

`RegulatoryReportings/DirectReporting/EFTs/EFT` (European Feeder/Flow Template).
`RegulatoryReportings/DirectReporting/EFTs/EFT` (European Feedback Template, FinDatEx EFT V1.0).
Deliberately chosen because it is the **most compact** of the regulatory
FundsXML structures (EMT/EET/PRIIPS/TPT are considerably larger and will follow
as their own examples in later phases).
Expand Down
4 changes: 3 additions & 1 deletion FundsXML_Files/4.2.9/signed/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ local `FundsXML.xsd` in any complete copy of the release).
> ⚠️ **Placeholder:** `DigestValue` and `SignatureValue` are schema-valid base64
> strings but **not cryptographically verifiable**. Real signing and
> verification (Apache Santuario / .NET `SignedXml` / `xmlsec1` / Python
> `signxml`) follows in **Phase 3** under `XML_Signature/`.
> `signxml`) lives in [`XML_Signature/`](../../../XML_Signature/README.md);
> note that this template uses inclusive C14N and a `ds:KeyName`, whereas the
> Java/.NET examples sign with exclusive C14N and embed the X.509 certificate.

Algorithms used (enveloped signature): C14N 2001-03-15, RSA-SHA256, SHA-256.

Expand Down
10 changes: 7 additions & 3 deletions FundsXML_Files/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,10 @@ XSD_Validation/cli/validate.sh \
# xmllint --noout --schema /tmp/FundsXML.xsd <file>
```

### Validate with Saxon
### Validate with Saxon (EE only)

Schema validation is a Saxon-**EE** feature (Saxon-HE, the edition used by the
examples in this repository, does not validate against XSD):

```bash
saxon -s:Mixed-Fund_Positions.xml -xsd:FundsXML.xsd -o:validation-report.xml
Expand Down Expand Up @@ -219,11 +222,12 @@ schema URL it was validated against.

| Version | Use case | File | Description |
|---------|----------|------|-------------|
| [4.2.9](./4.2.9/positions/) | positions | `Mixed-Fund_Positions.xml` | Comprehensive, 21 diverse positions, 13 asset types |
| [4.2.9](./4.2.9/positions/) | positions | `Mixed-Fund_Positions.xml` | Comprehensive, 21 diverse positions, 12 asset types |
| [4.2.9](./4.2.9/positions/) | positions | `Multi-Fund_Positions.xml` | 3 funds, 6 positions; lossless round-trip fixture for `Database_Integration/` |
| [4.2.9](./4.2.9/transactions/) | transactions | `Fund_Transactions.xml` | BUY/SELL/CASH, `AssetUniqueID` IDREF linking |
| [4.2.9](./4.2.9/documents/) | documents | `Fund_Documents.xml` | Factsheet (URL) + PRIIPS-KID (embedded base64) |
| [4.2.9](./4.2.9/regulatory/) | regulatory | `EFT_Regulatory.xml` | `RegulatoryReportings/DirectReporting/EFTs` |
| [4.2.9](./4.2.9/signed/) | signed | `Signed_Fund_Skeleton.xml` | Enveloped `ds:Signature` (placeholder, Phase 3) |
| [4.2.9](./4.2.9/signed/) | signed | `Signed_Fund_Skeleton.xml` | Enveloped `ds:Signature` skeleton (schema-valid, not verifiable — real signing in `XML_Signature/`) |
| [4.1.0](./4.1.0/positions/) | positions | `Equity-Fund_Positions.xml` | Compact equity fund, older valid version |
| [4.0.0](./4.0.0/positions/) | positions | `Equity-Fund_Positions.xml` | Oldest release — **no `ControlData/Version`** |

Expand Down
8 changes: 6 additions & 2 deletions Large_File_Processing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@

Enterprise FundsXML feeds can be hundreds of MB. Loading them into a DOM blows
memory; these examples process them **streaming, at constant memory** —
verified: ~16 MiB RSS (Python) / ~2 MiB heap (Java, `-Xmx64m`) for a 20 000-
position file, independent of file size.
verified: ~16 MiB RSS (Python) at 30 000 **and** 200 000 positions, and the
Java StAX aggregator completes a 200 000-position file under `-Xmx16m`. (The
heap figure the Java program prints when run through `./mvnw … exec:java`
includes Maven's own in-process JVM; run the compiled class directly with
`java -Xmx16m -cp Large_File_Processing/java/target/classes StreamAggregate`
to see the parser alone.)

| Tool | What | Status |
|------|------|--------|
Expand Down
33 changes: 24 additions & 9 deletions Schematron_DataQuality_Checks/Basic_Checks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,14 +129,29 @@ Validates currency codes and Amount elements.

## Running the Validation

### Prerequisites
### Quick Start (recommended: repo runners, nothing to install)

1. Install Saxon-HE (see [parent README](../README.md) for installation)
2. Download SchXslt for Schematron compilation
The runners in [`invocation/`](invocation/) pull SchXslt (which bundles its
own Saxon) from Maven Central via the committed Maven Wrapper; from the repo
root:

### Quick Start
```bash
./mvnw -q -pl Schematron_DataQuality_Checks/Basic_Checks/invocation compile exec:java \
-Dexec.args="Schematron_DataQuality_Checks/Basic_Checks/basic_checks.sch \
FundsXML_Files/4.2.9/positions/Mixed-Fund_Positions.xml" # exit 0 = no ERROR
```

See [`invocation/README.md`](invocation/README.md) for the Python
(`saxonche`), .NET and `svrl-summary.py` variants and the exit-code contract.

### Manual pipeline (hand-installed Saxon + SchXslt)

#### Prerequisites

1. Saxon-HE jar (download from <https://www.saxonica.com/download/java.xml>)
2. SchXslt for Schematron compilation

#### Using Saxon + SchXslt (Recommended)
#### Using Saxon + SchXslt

```bash
# Download SchXslt
Expand All @@ -145,7 +160,7 @@ git clone https://github.com/schxslt/schxslt.git
# Validate
java -jar saxon-he.jar \
-xsl:schxslt/2.0/pipeline-for-svrl.xsl \
-s:../../FundsXML_Files/4.2.9/Mixed-Fund_Positions.xml \
-s:../../FundsXML_Files/4.2.9/positions/Mixed-Fund_Positions.xml \
sch.file=basic_checks.sch \
-o:validation_report.xml
```
Expand All @@ -161,7 +176,7 @@ java -jar saxon-he.jar \

# Step 2: Run validation
java -jar saxon-he.jar \
-s:../../FundsXML_Files/4.2.9/Mixed-Fund_Positions.xml \
-s:../../FundsXML_Files/4.2.9/positions/Mixed-Fund_Positions.xml \
-xsl:basic_checks_compiled.xsl \
-o:validation_report.xml
```
Expand Down Expand Up @@ -196,7 +211,7 @@ Write-Host "Errors: $errors, Warnings: $warnings"
#!/bin/bash
SAXON_JAR="${SAXON_JAR:-/opt/saxon/saxon-he.jar}"
SCHXSLT="${SCHXSLT:-/opt/schxslt/2.0/pipeline-for-svrl.xsl}"
INPUT="${1:-../../FundsXML_Files/4.2.9/Mixed-Fund_Positions.xml}"
INPUT="${1:-../../FundsXML_Files/4.2.9/positions/Mixed-Fund_Positions.xml}"
OUTPUT="${2:-validation_report.xml}"

java -jar "$SAXON_JAR" \
Expand Down Expand Up @@ -420,4 +435,4 @@ Percentage Sum = 100%
- [ISO Schematron Specification](http://schematron.com)
- [SchXslt Documentation](https://github.com/schxslt/schxslt)
- [FundsXML Schema](https://github.com/fundsxml/schema)
- [Parent Schematron README](../README.md)
- [Invocation README (runners per stack)](invocation/README.md)
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ exits 1 on any failed-assert (including warnings).
|-------|------|----------------------|
| Java (native) | [`SchematronValidate.java`](SchematronValidate.java) | ✅ verified (SchXslt Java API, via Maven Wrapper) |
| Python | [`validate_schematron.py`](validate_schematron.py) | saxonche via repo venv (`pip install -e .`); SchXslt jar via `$FUNDSXML_SCHXSLT_JAR` or Maven local repo — reference variant |
| .NET/C# | [`SchematronValidate.cs`](SchematronValidate.cs) | SaxonHE via NuGet (`dotnet build`); SchXslt jar via `$FUNDSXML_SCHXSLT_JAR` or Maven local repo — reference variant |
| .NET/C# | [`SchematronValidate.cs`](SchematronValidate.cs) | reference variant, **does not restore as-is**: Saxonica publishes its .NET packages (`SaxonHE12Net*`) as dotnet *tools*, not libraries (`NU1212`); pair the code with a Saxon .NET library build of your own. SchXslt jar via `$FUNDSXML_SCHXSLT_JAR` or Maven local repo |
| shared | [`svrl-summary.py`](svrl-summary.py) | ✅ classifier used by all + CI |

The Java example runs standalone and cross-platform via the committed Maven
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Reference variant. SaxonHE comes from NuGet (restored by dotnet build);
the SchXslt jar is located via $FUNDSXML_SCHXSLT_JAR or the Maven local
repo (no NuGet SchXslt). Run from the repo root:
dotnet run project <thisdir> ../basic_checks.sch <xml-file> [fail-on error|any] -->
repo (no NuGet SchXslt). Run from the repo root with "dotnet run", the
project switch pointing at this directory, then
Schematron_DataQuality_Checks/Basic_Checks/basic_checks.sch <xml-file>
[fail-on error|any]; see the SchematronValidate.cs header for the exact
command line (XML comments cannot contain a double dash). -->
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
Run from the repo root:
./mvnw -q -pl Schematron_DataQuality_Checks/Basic_Checks/invocation \
compile exec:java \
-Dexec.args="../basic_checks.sch FundsXML_Files/4.2.9/positions/Mixed-Fund_Positions.xml"
-Dexec.args="Schematron_DataQuality_Checks/Basic_Checks/basic_checks.sch 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"
Expand Down
11 changes: 8 additions & 3 deletions XML_Signature/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ Windows too) to write a throwaway self-signed RSA-2048 keystore
|-------|-------------|--------|
| Java — Apache Santuario | [`java/SignFundsXml.java`](java/SignFundsXml.java) / [`java/VerifyFundsXml.java`](java/VerifyFundsXml.java) | ✅ verified (sign, verify, tamper-detect) |
| CLI — `xmlsec1` | [`cli/sign-verify-xmlsec1.sh`](cli/sign-verify-xmlsec1.sh) | reference (needs `xmlsec1`) |
| Python — `signxml` | [`python/sign_verify_signxml.py`](python/sign_verify_signxml.py) | reference (`pip install signxml`) |
| .NET — `SignedXml` | [`dotnet/SignVerify.cs`](dotnet/SignVerify.cs) | reference (needs .NET SDK) |
| Python — `signxml` | [`python/sign_verify_signxml.py`](python/sign_verify_signxml.py) | reference (`pip install -e ".[signature]"` adds `signxml`) |
| .NET — `SignedXml` | [`dotnet/SignVerify.cs`](dotnet/SignVerify.cs) | verified (.NET SDK 8): sign, verify, tamper; cross-verifies with Java both ways |

## Run (Java / Apache Santuario — verified)

Expand Down Expand Up @@ -66,7 +66,12 @@ with **secure validation** enabled.

> **Note on `xmlsec1`:** it signs an *existing* `ds:Signature` template, so it
> pairs naturally with the committed signed skeleton; the Java/.NET/Python
> examples instead build and append the `ds:Signature` themselves.
> examples instead build and append the `ds:Signature` themselves. Because
> the skeleton's template uses **inclusive** C14N (`REC-xml-c14n-20010315`),
> only the enveloped transform and a `ds:KeyName` in `KeyInfo`, the xmlsec1
> output does **not** follow the exclusive-C14N / embedded-X509 profile above:
> Java and .NET can still verify it against the pinned certificate, but not
> from the embedded `KeyInfo` (which carries no key).

A real signed file is **not committed** — the signature is bound to the
throwaway key, which is regenerated per run. CI signs → verifies as a roundtrip.
Loading