Area
Framework component or public API
User problem and use case
Applications embedding File Viewer may need to preview domain-specific XML documents whose structure and presentation rules are only known by the host application.
Today File Viewer can display XML as source, but it cannot know whether an application-specific XML document conforms to a particular schema or whether that format provides an XSLT stylesheet intended to produce a human-readable representation.
A common case is an XML format distributed with:
- an XSD schema describing and validating the document structure;
- an XSLT stylesheet defining a readable HTML representation.
The desired workflow is to let the host application register these resources once and then open XML files normally through File Viewer.
The host application should not need to detect, validate and transform every XML document before passing it to File Viewer.
A typical self-hosted deployment could provide a directory such as:
/file-viewer/xml-profiles/
├── profiles.json
├── invoice/
│ ├── schema.xsd
│ └── style.xsl
└── order/
├── schema.xsd
└── style.xsl
The application would only need to configure the profile manifest location, for example:
const options = {
xml: {
profilesUrl: '/file-viewer/xml-profiles/profiles.json'
}
}
The manifest could associate each XML format with its XSD and XSLT resources:
{
"profiles": [
{
"id": "invoice-v1",
"match": {
"rootNamespace": {
"enabled": true,
"root": "invoice",
"namespace": "urn:example:invoice:v1"
},
"xsd": {
"enabled": true
}
},
"xsd": "./invoice/schema.xsd",
"xslt": "./invoice/style.xsl"
}
]
}
Relative XSD/XSLT paths would be resolved relative to the profile manifest so all resources can remain self-hosted with the application.
Proposed outcome
Please consider adding an optional XML rendering-profile capability.
Each profile may enable two independent checks:
- root element + namespace matching;
- XSD validation.
Either check can be enabled individually.
When multiple checks are enabled, every enabled check must succeed before the profile is accepted and its XSLT is applied.
Root element + namespace check
When rootNamespace.enabled is true, File Viewer checks the XML document root local name and namespace.
For example:
<invoice xmlns="urn:example:invoice:v1">
can be matched against:
{
"rootNamespace": {
"enabled": true,
"root": "invoice",
"namespace": "urn:example:invoice:v1"
}
}
This is a lightweight check and can quickly reject unrelated profiles without running full schema validation.
XSD check
When xsd.enabled is true, File Viewer validates the XML document against the XSD associated with the profile.
This is a stronger check because it validates the actual document structure, required elements, attributes and datatypes rather than only its namespace and root element.
For example:
{
"match": {
"rootNamespace": {
"enabled": false
},
"xsd": {
"enabled": true
}
},
"xsd": "./invoice/schema.xsd",
"xslt": "./invoice/style.xsl"
}
allows profile matching based on XSD validation only.
Using both checks
The recommended configuration would enable both checks:
{
"match": {
"rootNamespace": {
"enabled": true,
"root": "invoice",
"namespace": "urn:example:invoice:v1"
},
"xsd": {
"enabled": true
}
}
}
The intended flow is:
XML
│
▼
root + namespace check
│
├── fail ──────────────────► next candidate / XML source fallback
│
▼
candidate profile
│
▼
XSD validation
│
├── fail ──────────────────► XML source fallback + diagnostics
│
▼
confirmed profile
│
▼
XSLT transformation
│
├── fail ──────────────────► XML source fallback + diagnostics
│
▼
safe rendered output
This gives the inexpensive namespace/root check the role of candidate selection while XSD validation provides stronger confirmation.
There is no need for an additional all / any matching operator: all enabled checks simply have to succeed.
Root/namespace only
Applications that trust a stable and unique XML namespace and do not need schema validation could disable the XSD check:
{
"match": {
"rootNamespace": {
"enabled": true,
"root": "invoice",
"namespace": "urn:example:invoice:v1"
},
"xsd": {
"enabled": false
}
}
}
XSD only
Applications that cannot reliably identify a document from its namespace/root could disable the lightweight check:
{
"match": {
"rootNamespace": {
"enabled": false
},
"xsd": {
"enabled": true
}
}
}
In this mode File Viewer may need to validate the document against multiple registered XSD profiles.
The result should be deterministic:
0 valid XSD profiles
-> normal XML source preview
1 valid XSD profile
-> select profile and apply its XSLT
more than 1 valid XSD profile
-> ambiguous profile
-> do not select arbitrarily
-> XML source preview + diagnostic
Complete processing flow
When an XML document is opened, File Viewer would:
- Parse the XML safely.
- Find registered profiles whose enabled lightweight checks match.
- Run XSD validation for profiles where the XSD check is enabled.
- Reject any profile for which an enabled check fails.
- Select the profile only when the result is unambiguous.
- Apply the associated XSLT stylesheet.
- Render the transformation result through an isolated/safe File Viewer rendering surface.
- Fall back to the normal XML source preview if no profile matches, validation fails, profile selection is ambiguous, or XSLT transformation fails.
Acceptance criteria
- XML profile support is opt-in and does not alter existing XML rendering by default.
- A host application can register profiles through one local/self-hosted manifest URL or equivalent public API.
- XSD and XSLT paths may be relative to the manifest location.
- Root/namespace matching and XSD validation are independently configurable checks.
- Either check may be enabled individually.
- Both checks may be enabled together.
- When multiple checks are enabled, every enabled check must succeed.
- A failed enabled check prevents the profile's XSLT from being applied.
- Root/namespace matching can narrow candidate profiles before the more expensive XSD validation.
- XSD-only matching is supported when namespace/root information is insufficient.
- If XSD-only matching validates against exactly one profile, that profile may be selected.
- If multiple profiles validate successfully, File Viewer must not select one arbitrarily.
- A valid matching document is transformed using the associated XSLT stylesheet.
- No matching profile falls back to the existing XML source renderer.
- XSD validation failure falls back to XML source preview rather than preventing the file from being opened.
- XSLT transformation failure also falls back to XML source preview.
- Validation/transformation diagnostics may be surfaced where practical.
- XSD/XSLT/WASM dependencies are lazy-loaded only when needed.
- Required runtime assets can be self-hosted for offline/intranet deployments.
- The original XML remains unchanged and remains the authoritative downloadable source.
- HTML generated through XSLT is treated as untrusted document output.
- Document-generated scripts must not execute in the host page.
- External resources referenced by XSD/XSLT must not have unrestricted network access by default.
The exact property names and manifest schema above are only suggestions.
The important outcome is that an embedding application can register XML schema/style pairs once and File Viewer can automatically identify, validate and render matching XML documents.
Samples, specifications, or references
A small redistributable fixture can be attached to the issue as:
invoice-invalid.xml
invoice-valid.xml
profiles.json
invoice_is_a_xsd.xml
invoice_is_a_xsl.xml
invoice-invalid.xml
invoice-valid.xml
profiles.json
flyfish-xml-profile-sample-v2.zip
It contains:
profiles.json
invoice-valid.xml
invoice-invalid.xml
invoice.xsd
invoice.xsl
README.txt
The fixture was created specifically for this feature proposal and contains no customer or third-party data.
invoice-valid.xml is expected to behave as follows:
root/namespace check PASS
XSD validation PASS
XSLT transformation EXECUTED
result rendered HTML
invoice-invalid.xml intentionally uses the correct root element and namespace but is missing a required element:
root/namespace check PASS
XSD validation FAIL
XSLT transformation NOT EXECUTED
result XML source preview + optional diagnostic
This demonstrates why root/namespace matching and XSD validation are useful as separate checks.
Specifications
XSLT 1.0 — W3C Recommendation:
https://www.w3.org/TR/xslt-10/
XML Schema 1.0 Part 1 — Structures:
https://www.w3.org/TR/xmlschema-1/
XML Schema 1.0 Part 2 — Datatypes:
https://www.w3.org/TR/xmlschema-2/
XSLT implementation candidate
xslt-polyfill
Repository:
https://github.com/mfreed7/xslt_polyfill
License: BSD-3-Clause
The project provides an XSLTProcessor-compatible implementation backed by libxslt/libxml2 WebAssembly.
Public sample XML:
https://github.com/mfreed7/xslt_polyfill/blob/main/test/demo.xml
Public XSLTProcessor example:
https://github.com/mfreed7/xslt_polyfill/blob/main/test/XSLTProcessor_example.html
XSD implementation candidate
xmllint-wasm
Repository:
https://github.com/noppa/xmllint-wasm
License: MIT
The project provides libxml2-based XML/XSD validation through WebAssembly and documents browser-side XSD validation.
Alternatives considered
Existing XML source preview
Displaying XML source is useful and should remain the fallback behavior, but it cannot provide the format-specific presentation that the XML producer intended through its XSLT.
The host application currently has to detect the format and perform validation/transformation itself before handing the result to File Viewer.
This duplicates XML handling outside the viewer and means the viewer may receive generated HTML instead of the original document.
Namespace-only profile matching
Matching root element and namespace is inexpensive and useful for XML formats with stable, unique namespaces.
However, it only identifies the apparent document family.
For example, this XML could have the expected namespace:
<invoice xmlns="urn:example:invoice:v1">
while still missing required elements or containing invalid values.
For that reason root/namespace matching and XSD validation should be exposed as separate checks.
Applications can choose lightweight matching only, schema validation only, or enable both.
Trying every registered XSD unconditionally
File Viewer could validate every XML document against every registered schema.
This provides strong detection but may become expensive when applications register many schemas.
Enabling both checks provides a more efficient path:
root/namespace
↓
small candidate set
↓
XSD validation
XSD-only matching remains available where necessary.
Pre-transforming XML before passing it to File Viewer
The application could apply XSLT itself and pass generated HTML to the viewer.
This works, but requires each embedding application to independently implement:
- XML format detection;
- schema loading;
- XSD validation;
- XSLT processing;
- error handling;
- fallback behavior.
It also separates the displayed result from the original file that File Viewer is previewing.
Native browser XSLTProcessor
Historically browsers exposed XSLT 1.0 through XSLTProcessor.
Relying on the browser's native implementation is no longer a good long-term foundation as native XSLT support is being deprecated/removed from browser engines.
A self-hostable WASM implementation is better aligned with File Viewer's browser-side/offline model.
SaxonJS
SaxonJS supports significantly more advanced XSLT capabilities.
However, it introduces a different browser deployment model and commonly uses compiled SEF stylesheets.
For an initial implementation intended to consume existing .xsl resources directly, an XSLT 1.0/libxslt implementation is simpler.
xslt-processor
xslt-processor can perform JavaScript XSLT processing but is LGPL-3.0 licensed.
For an Apache-2.0 project, a permissively licensed implementation is preferable to keep browser bundling and redistribution simpler.
Server-side conversion
XSD validation and XSLT transformation could be delegated to a backend.
That would work technically but would remove an important benefit of File Viewer: private/offline browser-side preview without requiring a document-conversion service.
Dependency and license notes
XSLT: xslt-polyfill
Suggested use: XSLT 1.0 transformation.
License: BSD-3-Clause.
Repository:
https://github.com/mfreed7/xslt_polyfill
The implementation provides an XSLTProcessor-compatible API backed by WebAssembly ports of libxslt and libxml2.
This appears compatible with File Viewer's browser/WASM and self-hosted asset model.
The proposed integration should use its transformation API rather than automatic whole-document replacement behavior.
The generated output should pass through File Viewer's normal isolation/sanitization strategy.
XSLT mechanisms such as:
xsl:include;
xsl:import;
document();
need explicit resource-resolution rules.
A conservative implementation could initially allow only registered/self-hosted resources.
The XSLT runtime should be loaded lazily only when a selected XML profile actually requires transformation.
XSD: xmllint-wasm
Suggested use: XML Schema validation and, when requested, XSD-based profile matching.
License: MIT.
Repository:
https://github.com/noppa/xmllint-wasm
It exposes libxml2 XML Schema validation through WebAssembly.
In the proposed design it can be used for two related operations:
- validating a profile already selected by root/namespace;
- determining the matching profile from registered XSDs when XSD-only matching is enabled.
Schemas and their dependencies should be cached where possible.
Schema dependencies referenced through xsd:include / xsd:import should use an explicit controlled resource resolver.
Validation work should preferably execute outside expensive main-thread rendering work where practical.
Loading and offline behavior
Neither dependency needs to be part of File Viewer's normal initial payload.
A possible loading flow is:
ordinary XML / no configured profiles
-> existing XML renderer only
rootNamespace enabled
-> inspect XML
-> identify candidate profile(s)
xsd enabled
-> lazy-load XSD validator
-> validate candidate(s)
profile confirmed
-> lazy-load XSLT engine
-> transform
-> render
failure / ambiguity
-> existing XML source renderer
All profile resources and WASM/runtime assets should be deployable from the same origin so the feature works in air-gapped, intranet and private deployments.
Required confirmations
Area
Framework component or public API
User problem and use case
Applications embedding File Viewer may need to preview domain-specific XML documents whose structure and presentation rules are only known by the host application.
Today File Viewer can display XML as source, but it cannot know whether an application-specific XML document conforms to a particular schema or whether that format provides an XSLT stylesheet intended to produce a human-readable representation.
A common case is an XML format distributed with:
The desired workflow is to let the host application register these resources once and then open XML files normally through File Viewer.
The host application should not need to detect, validate and transform every XML document before passing it to File Viewer.
A typical self-hosted deployment could provide a directory such as:
The application would only need to configure the profile manifest location, for example:
The manifest could associate each XML format with its XSD and XSLT resources:
{ "profiles": [ { "id": "invoice-v1", "match": { "rootNamespace": { "enabled": true, "root": "invoice", "namespace": "urn:example:invoice:v1" }, "xsd": { "enabled": true } }, "xsd": "./invoice/schema.xsd", "xslt": "./invoice/style.xsl" } ] }Relative XSD/XSLT paths would be resolved relative to the profile manifest so all resources can remain self-hosted with the application.
Proposed outcome
Please consider adding an optional XML rendering-profile capability.
Each profile may enable two independent checks:
Either check can be enabled individually.
When multiple checks are enabled, every enabled check must succeed before the profile is accepted and its XSLT is applied.
Root element + namespace check
When
rootNamespace.enabledistrue, File Viewer checks the XML document root local name and namespace.For example:
can be matched against:
{ "rootNamespace": { "enabled": true, "root": "invoice", "namespace": "urn:example:invoice:v1" } }This is a lightweight check and can quickly reject unrelated profiles without running full schema validation.
XSD check
When
xsd.enabledistrue, File Viewer validates the XML document against the XSD associated with the profile.This is a stronger check because it validates the actual document structure, required elements, attributes and datatypes rather than only its namespace and root element.
For example:
{ "match": { "rootNamespace": { "enabled": false }, "xsd": { "enabled": true } }, "xsd": "./invoice/schema.xsd", "xslt": "./invoice/style.xsl" }allows profile matching based on XSD validation only.
Using both checks
The recommended configuration would enable both checks:
{ "match": { "rootNamespace": { "enabled": true, "root": "invoice", "namespace": "urn:example:invoice:v1" }, "xsd": { "enabled": true } } }The intended flow is:
This gives the inexpensive namespace/root check the role of candidate selection while XSD validation provides stronger confirmation.
There is no need for an additional
all/anymatching operator: all enabled checks simply have to succeed.Root/namespace only
Applications that trust a stable and unique XML namespace and do not need schema validation could disable the XSD check:
{ "match": { "rootNamespace": { "enabled": true, "root": "invoice", "namespace": "urn:example:invoice:v1" }, "xsd": { "enabled": false } } }XSD only
Applications that cannot reliably identify a document from its namespace/root could disable the lightweight check:
{ "match": { "rootNamespace": { "enabled": false }, "xsd": { "enabled": true } } }In this mode File Viewer may need to validate the document against multiple registered XSD profiles.
The result should be deterministic:
Complete processing flow
When an XML document is opened, File Viewer would:
Acceptance criteria
The exact property names and manifest schema above are only suggestions.
The important outcome is that an embedding application can register XML schema/style pairs once and File Viewer can automatically identify, validate and render matching XML documents.
Samples, specifications, or references
A small redistributable fixture can be attached to the issue as:
invoice-invalid.xml
invoice-valid.xml
profiles.json
invoice_is_a_xsd.xml
invoice_is_a_xsl.xml
invoice-invalid.xml
invoice-valid.xml
profiles.json
flyfish-xml-profile-sample-v2.zip
It contains:
The fixture was created specifically for this feature proposal and contains no customer or third-party data.
invoice-valid.xmlis expected to behave as follows:invoice-invalid.xmlintentionally uses the correct root element and namespace but is missing a required element:This demonstrates why root/namespace matching and XSD validation are useful as separate checks.
Specifications
XSLT 1.0 — W3C Recommendation:
https://www.w3.org/TR/xslt-10/
XML Schema 1.0 Part 1 — Structures:
https://www.w3.org/TR/xmlschema-1/
XML Schema 1.0 Part 2 — Datatypes:
https://www.w3.org/TR/xmlschema-2/
XSLT implementation candidate
xslt-polyfillRepository:
https://github.com/mfreed7/xslt_polyfill
License: BSD-3-Clause
The project provides an
XSLTProcessor-compatible implementation backed by libxslt/libxml2 WebAssembly.Public sample XML:
https://github.com/mfreed7/xslt_polyfill/blob/main/test/demo.xml
Public
XSLTProcessorexample:https://github.com/mfreed7/xslt_polyfill/blob/main/test/XSLTProcessor_example.html
XSD implementation candidate
xmllint-wasmRepository:
https://github.com/noppa/xmllint-wasm
License: MIT
The project provides libxml2-based XML/XSD validation through WebAssembly and documents browser-side XSD validation.
Alternatives considered
Existing XML source preview
Displaying XML source is useful and should remain the fallback behavior, but it cannot provide the format-specific presentation that the XML producer intended through its XSLT.
The host application currently has to detect the format and perform validation/transformation itself before handing the result to File Viewer.
This duplicates XML handling outside the viewer and means the viewer may receive generated HTML instead of the original document.
Namespace-only profile matching
Matching root element and namespace is inexpensive and useful for XML formats with stable, unique namespaces.
However, it only identifies the apparent document family.
For example, this XML could have the expected namespace:
while still missing required elements or containing invalid values.
For that reason root/namespace matching and XSD validation should be exposed as separate checks.
Applications can choose lightweight matching only, schema validation only, or enable both.
Trying every registered XSD unconditionally
File Viewer could validate every XML document against every registered schema.
This provides strong detection but may become expensive when applications register many schemas.
Enabling both checks provides a more efficient path:
XSD-only matching remains available where necessary.
Pre-transforming XML before passing it to File Viewer
The application could apply XSLT itself and pass generated HTML to the viewer.
This works, but requires each embedding application to independently implement:
It also separates the displayed result from the original file that File Viewer is previewing.
Native browser
XSLTProcessorHistorically browsers exposed XSLT 1.0 through
XSLTProcessor.Relying on the browser's native implementation is no longer a good long-term foundation as native XSLT support is being deprecated/removed from browser engines.
A self-hostable WASM implementation is better aligned with File Viewer's browser-side/offline model.
SaxonJS
SaxonJS supports significantly more advanced XSLT capabilities.
However, it introduces a different browser deployment model and commonly uses compiled SEF stylesheets.
For an initial implementation intended to consume existing
.xslresources directly, an XSLT 1.0/libxslt implementation is simpler.xslt-processorxslt-processorcan perform JavaScript XSLT processing but is LGPL-3.0 licensed.For an Apache-2.0 project, a permissively licensed implementation is preferable to keep browser bundling and redistribution simpler.
Server-side conversion
XSD validation and XSLT transformation could be delegated to a backend.
That would work technically but would remove an important benefit of File Viewer: private/offline browser-side preview without requiring a document-conversion service.
Dependency and license notes
XSLT:
xslt-polyfillSuggested use: XSLT 1.0 transformation.
License: BSD-3-Clause.
Repository:
https://github.com/mfreed7/xslt_polyfill
The implementation provides an
XSLTProcessor-compatible API backed by WebAssembly ports of libxslt and libxml2.This appears compatible with File Viewer's browser/WASM and self-hosted asset model.
The proposed integration should use its transformation API rather than automatic whole-document replacement behavior.
The generated output should pass through File Viewer's normal isolation/sanitization strategy.
XSLT mechanisms such as:
xsl:include;xsl:import;document();need explicit resource-resolution rules.
A conservative implementation could initially allow only registered/self-hosted resources.
The XSLT runtime should be loaded lazily only when a selected XML profile actually requires transformation.
XSD:
xmllint-wasmSuggested use: XML Schema validation and, when requested, XSD-based profile matching.
License: MIT.
Repository:
https://github.com/noppa/xmllint-wasm
It exposes libxml2 XML Schema validation through WebAssembly.
In the proposed design it can be used for two related operations:
Schemas and their dependencies should be cached where possible.
Schema dependencies referenced through
xsd:include/xsd:importshould use an explicit controlled resource resolver.Validation work should preferably execute outside expensive main-thread rendering work where practical.
Loading and offline behavior
Neither dependency needs to be part of File Viewer's normal initial payload.
A possible loading flow is:
All profile resources and WASM/runtime assets should be deployable from the same origin so the feature works in air-gapped, intranet and private deployments.
Required confirmations