Façade-X mapping for XML
Copyright
©
2026
the Contributors to the Façade-X mapping for XML
Specification, published by the
Data Façades Community Group under the
W3C Community Contributor License Agreement (CLA). A human-readable
summary
is available.
This document specifies how an XML resource is represented as a Façade-X data source.
This specification was published by the Data Façades Community Group. It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups.
This is version 0.1 of this document, released on 2026-10-06, at https://w3c-facade-x.github.io/facade-x-specs/0.1/mapping-xml.html. This version will not change. The latest release is always at https://w3c-facade-x.github.io/facade-x-specs/mapping-xml.html. The editor's draft, which may include changes made after this release, is at https://w3c-facade-x.github.io/facade-x-specs/dev/mapping-xml.html. The issues addressed in this release, and those still open, are listed in the release notes.
This document is a first draft. It follows the behaviour of the reference implementation, SPARQL Anything, and the test cases in facade-x-tests, as summarised in issue #31.
GitHub Issues are preferred for discussion of this specification.
This document is listed in Façade-X Mappings, one of the seven Façade-X specification documents produced by the Data Façades Community Group:
This section is non-normative.
An XML document is a tree of elements [XML]. Each element has a name, a set of attributes, and an ordered sequence of content: child elements and character data. Element and attribute names may belong to a namespace [XML-NAMES].
In Façade-X, each element is a container typed with the element name. Its attributes are held by string slots, and its content by numbered slots, in document order. Character data are values.
This document applies the common principles of the format mappings.
| Prefix | Namespace |
|---|---|
| fx | http://sparql.xyz/facade-x/ns/ |
| fxe | http://sparql.xyz/facade-x/engine/ |
| xyz | http://sparql.xyz/facade-x/data/ |
| rdf | http://www.w3.org/1999/02/22-rdf-syntax-ns# |
SPARQL Anything supports the option xml.path, which takes one or more XPath expressions (xml.path, xml.path.1, xml.path.2, …) to restrict what is represented. The XML mapping draft lists it as fxe:xml.path but does not define its meaning.
Questions:
fxe:json.path in the JSON mapping;count(//item))?xml.path.N be kept?The JSON mapping has the same open question for fxe:json.path; the two options should behave consistently.
SPARQL Anything does not process DTDs, so a document that declares and uses an entity fails to parse ("entity … referenced, but not declared"). See #31. The XML mapping draft does not yet say what engines should do with DTDs.
<!DOCTYPE doc [ <!ENTITY company "Example Ltd"> ]>
<doc>&company;</doc>Options:
Things to consider:
A test with an internal entity declaration in facade-x-tests/tests/xml would pin down the expected behaviour.
The XML mapping draft drops every text node that consists only of whitespace, and such text does not use up a slot number. As a result, <empty/>, <empty></empty> and <empty> </empty> have the same representation, and indentation between elements produces nothing. This is the behaviour of SPARQL Anything (see #31 and tests/xml/2-features).
However, the whitespace is dropped even inside an element with xml:space="preserve", which asks applications to keep whitespace (XML 1.0 §2.10). Non-whitespace text already keeps its surrounding spaces, with or without xml:space.
Options:
xml:space="preserve": inside such an element (and its descendants, unless reset with xml:space="default"), whitespace-only text nodes are kept and take a slot number.fxe:xml.keep-whitespace) to keep whitespace-only text everywhere.Option 2 follows the XML recommendation, but changes the slot numbering of existing documents that use xml:space="preserve".
The XML mapping draft turns an element or attribute name in a namespace into an IRI by concatenating the namespace name and the local part, inserting # when the namespace name does not end with / or #. This is what SPARQL Anything does (see #31):
| Name | IRI |
|---|---|
{http://example.org/catalog}item |
http://example.org/catalog#item |
{http://purl.org/dc/elements/1.1/}title |
http://purl.org/dc/elements/1.1/title |
xml:lang |
http://www.w3.org/XML/1998/namespace#lang |
Plain concatenation would give http://example.org/catalogitem, which is unreadable and can clash (http://example.org/cat + alogitem).
Open points:
# insertion, or use plain concatenation as RDF/XML does?urn:example:ns? Inserting # gives urn:example:ns#item, which is a valid IRI but may not be what users expect.:) also be left unchanged?A test with a urn: namespace in facade-x-tests/tests/xml would pin down the chosen rule.
An engine MUST apply this mapping to a resource whose media type is application/xml or
text/xml [RFC7303], or any media type with the
structured syntax suffix +xml
(e.g. image/svg+xml), unless another format mapping applies to that media type.
When the media type is not given, an engine SHOULD apply this mapping to resources with the file
extensions xml and svg.
An XML resource yields exactly one data source. Its triples are placed in the named graph whose IRI
is the value of fxe:root.
The document element is represented by the root container,
which is typed both fx:Root and with the name of the document element.
The XML declaration, the document type declaration, and any comments and processing instructions outside the document element are not represented.
Element and attribute names are turned into IRIs as follows:
/ or #, a # is inserted between
them. For example, the element item in the namespace http://example.org/catalog gives
http://example.org/catalog#item, and dc:title, with dc bound to
http://purl.org/dc/elements/1.1/, gives http://purl.org/dc/elements/1.1/title.fxe:namespace, as defined in the
common principles. With the default namespace, person gives
xyz:person.As defined in [XML-NAMES], an unprefixed attribute has no namespace name, even
when a default namespace is declared: it is minted with fxe:namespace. The prefix xml is bound
to http://www.w3.org/XML/1998/namespace, so xml:lang gives
http://www.w3.org/XML/1998/namespace#lang.
Each element is represented by a container typed (rdf:type) with the IRI of the element name.
Each attribute of the element is held by a string slot whose IRI is the IRI of the attribute name.
Namespace declarations (xmlns and xmlns:* attributes) are not represented.
The content of the element is held by numbered slots, in document order: the first item in
rdf:_1, the second in rdf:_2, and so on. The items are:
A text node is a maximal sequence of character data between two pieces of markup. Character references, entity references and CDATA sections are replaced by the characters they stand for and are part of the surrounding text node.
The following are not represented, and do not use up a slot number:
An element with no attributes and no represented content gives a container that is only typed.
<empty/>, <empty></empty> and <empty> </empty> have the same representation.
XML without a schema defines no value types. Following the
common principles, every attribute value and text node is a literal of
type xsd:string, including values such as 10.50 or true. When fxe:xml.lang-tags is true,
values in the scope of xml:lang are language-tagged instead (see Language).
The lexical form of a text node is its character data, with whitespace kept: Text and tail
keep their spaces. Line ends are normalised as required by
XML 1.0 §2.11.
The lexical form of an attribute value is the value after
attribute-value normalisation. A line feed written as
the character reference is kept as a line feed.
By default, xml:lang is held by a string slot like any other attribute (see Names) and
has no other effect on the representation.
When fxe:xml.lang-tags is true, values are also language-tagged, following
the scope of xml:lang defined in XML 1.0 §2.12:
xml:lang attribute or, when it has none, the
language of its parent element. A document element without xml:lang has no language.xml:lang="" gives the element no language.xml:lang that is not a well-formed language tag [BCP47] is treated as
xml:lang="".xml:lang, xml:space, xml:base, xml:id) are not
language-tagged.xml:lang slot is kept.All other values are of type xsd:string.
The language of an element is determined by the XML source alone. Options that omit triples do
not change it: with fxe:null-string set to "", the slot for
xml:lang="" is omitted, but the element still has no language.
These options are terms of the Engine vocabulary and apply only to this mapping.
| Term | Range | Default | Description |
|---|---|---|---|
fxe:xml.path |
xsd:string |
— | An XPath expression [XPATH]. Only the nodes it selects, and their content, are represented. |
fxe:xml.lang-tags |
xsd:boolean |
false | Language-tag text nodes and attribute values in the scope of xml:lang (see Language). |
The reference implementation accepts several values for xml.path as numbered options
(xml.path.1, xml.path.2, …). Whether this form is kept is open.
An engine SHOULD NOT retrieve external entities or external DTD subsets referenced by a document, since doing so can disclose local files or cause requests to other hosts.
This section is non-normative.
Input:
<?xml version="1.0" encoding="UTF-8"?>
<person id="p1">
<name>Alice</name>
</person>
Façade-X representation:
@prefix fx: <http://sparql.xyz/facade-x/ns/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix xyz: <http://sparql.xyz/facade-x/data/> .
[] a fx:Root, xyz:person ;
xyz:id "p1" ;
rdf:_1 [ a xyz:name ; rdf:_1 "Alice" ] .
The whitespace between the elements gives no text nodes.
Input:
<catalog xmlns="http://example.org/catalog"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:ex="http://example.org/ext"
version="1.0" xml:lang="en">
<dc:title>Sample catalog</dc:title>
<item id="i1" ex:status="active">
<price currency="EUR">10.50</price>
</item>
</catalog>
Façade-X representation:
@prefix fx: <http://sparql.xyz/facade-x/ns/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix xyz: <http://sparql.xyz/facade-x/data/> .
@prefix cat: <http://example.org/catalog#> .
@prefix ex: <http://example.org/ext#> .
@prefix dc: <http://purl.org/dc/elements/1.1/> .
[] a fx:Root, cat:catalog ;
xyz:version "1.0" ;
<http://www.w3.org/XML/1998/namespace#lang> "en" ;
rdf:_1 [ a dc:title ; rdf:_1 "Sample catalog" ] ;
rdf:_2 [ a cat:item ;
xyz:id "i1" ;
ex:status "active" ;
rdf:_1 [ a cat:price ; xyz:currency "EUR" ; rdf:_1 "10.50" ] ] .
The elements take the default namespace, but the unprefixed attributes version, id and
currency do not.
Input:
<doc>
<mixed>Text <b>bold</b> and <i>italic</i> tail</mixed>
<!-- a comment -->
<empty/>
<whitespace> </whitespace>
</doc>
Façade-X representation:
@prefix fx: <http://sparql.xyz/facade-x/ns/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix xyz: <http://sparql.xyz/facade-x/data/> .
[] a fx:Root, xyz:doc ;
rdf:_1 [ a xyz:mixed ;
rdf:_1 "Text " ;
rdf:_2 [ a xyz:b ; rdf:_1 "bold" ] ;
rdf:_3 " and " ;
rdf:_4 [ a xyz:i ; rdf:_1 "italic" ] ;
rdf:_5 " tail" ] ;
rdf:_2 [ a xyz:empty ] ;
rdf:_3 [ a xyz:whitespace ] .
The comment does not use up a slot number, so empty is held by rdf:_2.
Input, with fxe:xml.lang-tags set to true:
<doc xml:lang="en">
<title>Colour</title>
<title xml:lang="it" note="variante">Colore</title>
<code xml:lang="">RGB</code>
</doc>
Façade-X representation:
@prefix fx: <http://sparql.xyz/facade-x/ns/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix xyz: <http://sparql.xyz/facade-x/data/> .
[] a fx:Root, xyz:doc ;
<http://www.w3.org/XML/1998/namespace#lang> "en" ;
rdf:_1 [ a xyz:title ; rdf:_1 "Colour"@en ] ;
rdf:_2 [ a xyz:title ;
<http://www.w3.org/XML/1998/namespace#lang> "it" ;
xyz:note "variante"@it ;
rdf:_1 "Colore"@it ] ;
rdf:_3 [ a xyz:code ;
<http://www.w3.org/XML/1998/namespace#lang> "" ;
rdf:_1 "RGB" ] .
The first title inherits en from doc; the second overrides it with it, which also applies to
its attribute note. In code, xml:lang="" removes the language. The xml:lang values
themselves are not tagged. With the default, fxe:xml.lang-tags set to false, all these values
are of type xsd:string.
Listing the items of the catalog with their price:
PREFIX fx: <http://sparql.xyz/facade-x/ns/>
PREFIX fxe: <http://sparql.xyz/facade-x/engine/>
PREFIX xyz: <http://sparql.xyz/facade-x/data/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX cat: <http://example.org/catalog#>
SELECT ?id ?price WHERE {
SERVICE <x-sparql-anything:> {
fx:properties fxe:location "catalog.xml" .
?item a cat:item ;
xyz:id ?id ;
?slot ?p .
?p a cat:price ;
rdf:_1 ?price .
}
}
This section is non-normative.