Créer vos propres règles
La logique des règles
Pour définir vos règles, voici la logique à suivre :
attribute/mandatory: la ressource NeTEx doit avoir l'attribut donnéname: le nom de l’attribut attendu
{
"rule": "attribute/mandatory",
"name": "name"
}
attribute/blank: l’attribut de la ressource NeTEx doit contenir une valeur (ne peut pas être vide)name: le nom de l’attribut qui doit contenir une valeur
{
"rule": "attribute/blank",
"name": "quay_type"
}
attribute/value: la ressource NeTEx doit avoir une certaine valeur pour un attribut donnéname: le nom de l’attribut/élément testévalue: la valeur attendue
{
"rule": "attribute/value",
"name": "transport_mode",
"value": "bus"
}
attribute/match: la ressource NeTEx doit avoir une valeur qui correspond au format donnéname: le nom de l’attribut/élément testévalue: le format attendu (sous la forme d’une expression régulière)
{
"rule": "attribute/match",
"name": "id",
"value": "/DE:.*:LOC/",
"message": "Identifier must use this format 'DE:*:LOC'"
}
resource/mandatory: la ressource NeTEx doit être présente
{
"rule_context": "resource/kind_of",
"resource_class": "Network",
"rules": [
{
"rule": "resource/mandatory",
"message": "A Network is mandatory"
}
]
}
resource/class: la ressource NeTEx doit correspondre à une certaine classe d’objets
{
"rule_context": "resource/kind_of",
"resource_class": "JourneyPattern",
"rules": [
{
"rule": "resource/class",
"expected_class": "ServiceJourneyPattern"
"message": "Use ServiceJourneyPattern (not JourneyPattern)"
}
]
}
collection/count: la ressource NeTEx doit avoir un nombre de valeurs compatible dans une collection donnéecollection: le nom de la collection testéeminimum_count: le nombre minimum d'éléments attendus dans la collection (optionnel)maximum_count: le nombre maximum d'éléments attendus dans la collection (optionnel)
{
"rule_context": "resource/kind_of",
"resource_class": "JourneyPattern",
"rules": [
{
"rule": "collection/count",
"collection": "points_in_sequence",
"minimum_count": 2,
"message": "A (Service)JourneyPattern has two or more pointsInSequence"
}
]
}
reference/exists: la référence NeTEx d’une certaine classe d’objet doit correspondre à une ressource existante donnéereferenced_class: la classe d’object testé
{
"rule": "reference/exist",
"referenced_class": "Quay",
"message": "All referenced Quays must defined"
}
reference/version: la référence NeTEx doit avoir une version correspondante à la valeur donnéereferenced_classes: le type de référence testéevalue: la valeur attendue
{
"rule": "reference/version",
"referenced_classes": ["Quay", "StopPlace"],
"value": "any"
}Par exemple, la règle présente peut tester ces cas:
<PassengerStopAssignment id="valid">
<!-- ... -->
<QuayRef version="any" ref="..."/>
</PassengerStopAssignment>
<PassengerStopAssignment id="unvalid">
<!-- ... -->
<QuayRef ref="..."/>
</PassengerStopAssignment>
tag/match: la ressource NeTEx a un tag qui correspond à une expression donnéename: le nom du tag testévalue:la valeur du tag attendue (peut-être une expression régulière)
{
"rule_context": "resource/kind_of",
"resource_class": "ServiceJourney",
"rules": [
{
"rule": "tag/match",
"name": "frame_id",
"value": "FR:GeneralFrame:NETEX_HORAIRE:LOC",
"message": "ServiceJourneys must be defined in NETEX_HORAIRE GeneralFrame"
}
]
}
service_journey/passing_times_chronology: vérifie que les horaires de passage des ServiceJourneys sont chronologiques
{
"rule": "service_journey/passing_times_chronology",
"message": "TimedPassingTimes use chronological passing times"
}La logique des contextes
resource/kind_of: teste seulement les ressources NeTEx avec la ou les classes indiquéesresource_classes: liste de classes acceptéesresource_class: alias permettant de définir une seule classe acceptée
{
"rule_context": "resource/kind_of",
"resource_classes": ["Quay", "StopPlace","StopPlaceEntrance"]
"rules": [
...
]
},
{
"rule_context": "resource/kind_of",
"resource_class": "Line",
"rules": [
...
]
}
attribute/match: teste seulement les ressources dans l’attribut indiqué correspondant à la valeur ou l’expression donnéename: le nom de l’attribut testévalue:la valeur attendue (peut-être une expression régulière)
{
"rule_context": "attribute/match",
"name": "id",
"value": "FR:GeneralFrame:NETEX_ARRET:LOC",
"rules": [
...
]
}
reduce/element: teste un élément d’une ressource NeTExelement: le nom de l’élément testé
{
"rule_context": "reduce/element",
"element": "presentation",
"rules": [
...
]
}
reduce/collection: teste les ressources présentes dans une ressource NeTExcollection: le nom de la collection contenant les ressources testées
{
"rule_context": "reduce/collection",
"element": "passingTimes",
"rules": [
...
]
}La création de vos règles
Client en ligne de commande
C’est la méthode la plus simple pour mettre à jour les règles
Créer et mettre à jour un Ruleset :
secretary-client create ruleset --name="Test Ruleset" --slug=acmee:test sample.json
secretary-client patch ruleset acmee:test --definition sample.json
Récupérer un Ruleset
secretary-client get ruleset acmee:test
secretary-client get ruleset --definition acmee:test
Éditer simplement un de ses Ruleset :
secretary-client get ruleset --definition acmee:test > sample.json
# Edit sample.json
secretary-client update ruleset acmee:test --definition sample.json
Supprimer un Ruleset :
secretary-client delete ruleset acmee:test
Utilisation de l’API
La documentation complète se trouve dans Postman.
Créer et mettre à jour un Ruleset :
➜ curl -s -X POST -H "Authorization: Token token=$TOKEN" -H "Content-Type: application/json; charset=UTF-8" https://chouette-valid.enroute.mobi/api/rulesets -d@- <<EOF
{
"ruleset": {
"name":"Test Ruleset",
"slug":"test",
"definition":"[
{
\"rule\": \"attribute/mandatory\",
\"name\": \"name\",
\"criticity\": \"error\",
\"code\": \"sample\",
\"message\": \"Phasellus vel nulla vel dolor semper tincidunt a vitae risus\"
}
]"
}
}
EOF➜ curl -s -X PUT -H "Authorization: Token token=$TOKEN" -H "Content-Type: application/json; charset=UTF-8" https://chouette-valid.enroute.mobi/api/rulesets/test -d@- <<EOF
{
"ruleset": {
"name":"Test Ruleset",
"slug":"test",
"definition":"[
{
\"rule\": \"attribute/mandatory\",
\"name\": \"name\",
\"criticity\": \"warning\",
\"code\": \"sample\",
\"message\": \"Fusce in risus ut nisi efficitur tempor et sed ligula\"
}
]"
}
}
EOF
Récupérer un Ruleset
➜ curl -s -H "Authorization: Token token=$TOKEN" https://chouette-valid.enroute.mobi/api/rulesets/test | jq .Retourne une réponse de type :
{
"id": "b97e25fc-ebe0-4417-a8f4-7b1da843d645",
"name": "Test Ruleset",
"slug": "test",
"definition": "[ { \"rule\": \"attribute/mandatory\", \"name\": \"name\", \"criticity\": \"error\", \"code\": \"sample\", \"message\": \"Phasellus vel nulla vel dolor semper tincidunt a vitae risus\" } ]",
"created_at": "2025-09-08T07:36:43.076Z",
"updated_at": "2025-09-08T07:36:43.076Z"
}
Supprimer un Ruleset:
➜ curl -s -X DELETE -H "Authorization: Token token=$TOKEN" https://chouette-valid.enroute.mobi/api/rulesets/test
Exemples de règles
Règles sur les attributs
Vérifie que chaque objet de type
Linepossède obligatoirement un attributpresentationavec un niveau de criticité warning et un message “A Line should have a Presentation”.
{
"rule_context": "resource/kind_of",
"resource_classes": "Line",
"rules": [
{
"rule":"attribute/mandatory",
"name": "presentation",
"criticity": "warning",
"code": "line-presentation-mandatory",
"message": "A Line should have a Presentation"
}
]
}
Vérifie que chaque attribut
short_namedes objets de typeLineetStopPlacecontient au maximum 12 caractères avec un niveau de criticité error.
{
"rule_context": "resource/kind_of",
"resource_classes": ["StopPlace", "Line"],
"rules": [
{
"rule": "attribute/match",
"name": "short_name",
"value": "/^.{0,12}$/",
"criticity": "error",
"code": "shortname-length",
"message": "A ShortName must not exceed 12 characters"
}
]
}
Vérifie la présence de l’attribut
colourdans les ressourcespresentationsur les objets de typeLineavec un niveau de criticité warning.
{
"rule_context": "resource/kind_of",
"resource_class": "Line",
"rules": [
{
"rule_context": "reduce/element",
"element": "presentation",
"rules": [
{
"rule": "attribute/mandatory",
"name": "colour",
"criticity": "warning",
"code": "line-presentation-colour-mandatory",
"message": "A Line should have a Presentation color"
}
]
}
]
}
Règles sur la structure du fichier
Vérifie la présence du GeneralFrame ARRET dans le fichier stop.xml du jeu de données en NeTEx avec un niveau de criticité error.
{
"rule_context": "resource/kind_of",
"resource_classes": ["GeneralFrame"],
"rules": [
{
"rule_context": "attribute/match",
"name": "id",
"value": "FR:GeneralFrame:NETEX_ARRET:LOC",
"rules": [
{
"rule": "tag/match",
"name": "filename",
"value": "stop.xml",
"criticity": "error",
"code": "general-frame-arret-filename",
"message": "GeneralFrame ARRET must be in stop.xml"
}
]
}
]
}
<!-- stop.xml -->
<?xml version="1.0" encoding="utf-8"?>
<PublicationDelivery …>
<PublicationTimestamp>2023-01-01T00:00:00.0Z</PublicationTimestamp>
<ParticipantRef>Exemple</ParticipantRef>
<dataObjects>
<GeneralFrame id="FR:GeneralFrame:NETEX_ARRET:LOC"
version="1.09:FR-NETEX-2.1-1.0">
<TypeOfFrameRef ref="FR:TypeOfFrame:NETEX_ARRET:"/>
<members>
…
</members>
</GeneralFrame>
</dataObjects>
</PublicationDelivery>
Vérifie que les objets
Quay,StopPlaceetStopPlaceEntrancesont membres d’un GeneralFrame Arrêt
{
"rule_context": "resource/kind_of",
"resource_classes": ["Quay", "StopPlace","StopPlaceEntrance"],
"rules": [
{
"rule": "tag/match",
"name": "frame_id",
"value": "FR:GeneralFrame:NETEX_ARRET:LOC",
"criticity": "error",
"code": "...",
"message": "..."
}
]
}
<?xml version="1.0" encoding="utf-8"?>
<PublicationDelivery …>
<PublicationTimestamp>2023-01-01T00:00:00.0Z</PublicationTimestamp>
<ParticipantRef>Exemple</ParticipantRef>
<dataObjects>
<GeneralFrame id="FR:GeneralFrame:NETEX_ARRET:LOC">
<members>
<!--
STOP PLACE
QUAY
TOPOGRAPHIC PLACE
STOP PLACE ENTRANCE
GENERAL GROUP OF ENTITIES
-->
</members>
</GeneralFrame>
</dataObjects>
</PublicationDelivery>