Skip to content

SPARQL → GeoJSON

app.sparql_to_geojson_translator

SPARQL instances → GeoJSON FeatureCollection.

_local_name(iri)

Return the fragment or last path segment of an IRI.

Parameters:

Name Type Description Default
iri str

Absolute IRI string.

required

Returns:

Type Description
str

Local name after # or the final / segment.

Source code in src/backend/app/sparql_to_geojson_translator.py
20
21
22
23
24
25
26
27
28
29
30
31
def _local_name(iri: str) -> str:
    """Return the fragment or last path segment of an IRI.

    Args:
        iri: Absolute IRI string.

    Returns:
        Local name after ``#`` or the final ``/`` segment.
    """
    return (
        iri.rsplit("#", maxsplit=1)[-1] if "#" in iri else iri.rsplit("/", maxsplit=1)[-1]
    )

extract_property(shape, instance)

Extract one EntityShape value from an instance binding dict.

Parameters:

Name Type Description Default
shape EntityShape

Property descriptor describing how the row was projected.

required
instance dict

One SPARQL result row as a dict.

required

Returns:

Type Description
Any

Decoded value: IRI/label dict(s), bool, list of strings, or a scalar.

Source code in src/backend/app/sparql_to_geojson_translator.py
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
def extract_property(shape: EntityShape, instance: dict) -> Any:
    """Extract one EntityShape value from an instance binding dict.

    Args:
        shape: Property descriptor describing how the row was projected.
        instance: One SPARQL result row as a dict.

    Returns:
        Decoded value: IRI/label dict(s), bool, list of strings, or a scalar.
    """
    sid = shape.id
    cat = shape.category
    is_multi = shape.is_multi

    if cat == "iri_with_label":
        if is_multi:
            raw = instance.get(f"{sid}Raw", "") or ""
            items = []
            for pair in raw.split(ITEM_SEP):
                parts = pair.strip().split(FIELD_SEP, 1)
                if len(parts) == _IRI_LABEL_FIELDS and parts[0]:
                    items.append({"iri": parts[0].strip(), "label": parts[1].strip()})
            return items
        iri_val = instance.get(f"{sid}Iri")
        label_val = instance.get(f"{sid}Label")
        if not iri_val:
            return None
        label = str(label_val) if label_val else str(iri_val).split("#")[-1].split("/")[-1]
        return {"iri": str(iri_val), "label": label}

    if cat == "boolean":
        return instance.get(f"{sid}Result", "") == "true"

    if is_multi:
        raw = instance.get(f"{sid}Raw", "") or ""
        return [a.strip() for a in raw.split(ITEM_SEP) if a.strip()]

    return instance.get(f"{sid}Result", "")

_parse_special_properties(instance, lang)

Decode fields queried outside the SHACL-driven EntityShape list.

Parameters:

Name Type Description Default
instance dict

SPARQL result row.

required
lang str

UI language for the stories URL.

required

Returns:

Type Description
dict

Extra GeoJSON properties (currently storiesUrl).

Source code in src/backend/app/sparql_to_geojson_translator.py
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
def _parse_special_properties(instance: dict, lang: str) -> dict:
    """Decode fields queried outside the SHACL-driven EntityShape list.

    Args:
        instance: SPARQL result row.
        lang: UI language for the stories URL.

    Returns:
        Extra GeoJSON properties (currently ``storiesUrl``).
    """
    wp_entity_tag_id = instance.get("wpEntityTagId", "")
    return {
        "storiesUrl": (
            entity_stories_url(wp_entity_tag_id, lang) if wp_entity_tag_id else ""
        ),
    }

_parse_coordinates(instance)

Build a GeoJSON Point from lat/long bindings, if usable.

Parameters:

Name Type Description Default
instance dict[str, Any]

SPARQL result row.

required

Returns:

Type Description
Point | None

Point or None when coordinates are missing or unparseable.

Source code in src/backend/app/sparql_to_geojson_translator.py
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
def _parse_coordinates(instance: dict[str, Any]) -> Point | None:
    """Build a GeoJSON Point from lat/long bindings, if usable.

    Args:
        instance: SPARQL result row.

    Returns:
        ``Point`` or ``None`` when coordinates are missing or unparseable.
    """
    lat_raw = instance.get("lat")
    long_raw = instance.get("long")
    if not lat_raw or not long_raw:
        return None
    try:
        return Point((float(long_raw), float(lat_raw)))
    except (TypeError, ValueError):
        logger.warning(
            "entity %s has unparseable coordinates (lat=%r, long=%r); "
            "rendering it as a region instead of a pin",
            instance.get("s"),
            lat_raw,
            long_raw,
        )
        return None

instances_to_geojson(instances, shapes, lang='en')

Build one Feature per SPARQL instance, decoded via EntityShape descriptors.

Parameters:

Name Type Description Default
instances list[dict[str, Any]]

SPARQL result rows.

required
shapes list[EntityShape]

Descriptors used to decode property columns.

required
lang str

UI language for special properties.

'en'

Returns:

Type Description
FeatureCollection

GeoJSON FeatureCollection (pins with geometry; regions with

FeatureCollection

is_region / regionKey and null geometry).

Source code in src/backend/app/sparql_to_geojson_translator.py
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
def instances_to_geojson(
    instances: list[dict[str, Any]],
    shapes: list[EntityShape],
    lang: str = "en",
) -> FeatureCollection:
    """Build one Feature per SPARQL instance, decoded via EntityShape descriptors.

    Args:
        instances: SPARQL result rows.
        shapes: Descriptors used to decode property columns.
        lang: UI language for special properties.

    Returns:
        GeoJSON FeatureCollection (pins with geometry; regions with
        ``is_region`` / ``regionKey`` and null geometry).
    """
    features = []
    for instance in instances:
        if not instance.get("s") or not instance.get("label") or not instance.get("type"):
            logger.warning(
                "skipping instance without id, label or type: %r",
                sorted(instance.keys()),
            )
            continue

        properties: dict[str, Any] = {
            "id": instance["s"],
            "label": instance["label"],
            "type": str(instance.get("typeLabelResult") or _local_name(instance["type"])),
            "typeIri": instance["type"],
        }
        for shape in shapes:
            properties[shape.id] = extract_property(shape, instance)
        properties.update(_parse_special_properties(instance, lang))

        geometry = _parse_coordinates(instance)
        if geometry is None:
            properties["is_region"] = True
            properties["regionKey"] = _local_name(instance["s"])

        features.append(Feature(geometry=geometry, properties=properties))

    return FeatureCollection(features)