尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Football Schema: a JSON-LD vocabulary for competitions, seasons, clubs, matches and league tables
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗A canonical, machine-readable model of association football in JSON-LD: competitions, seasons, clubs, grounds, people, matches and league tables, with the Premier League as the reference competition. Modelled on Bitcoin Schema: one schema, many projections.
Record the events; derive everything else. A match records what happened (or, when a source
gives only the score, a reported fullTime). The score, the result, minutes played and every
number in a league table are derived fields (/name in the diagram), defined in the schema and
implemented once in tools/model.js.
| module | layer | contents |
|---|---|---|
core | domain | Competition (with TableZones), Season (with PointsDeductions), Club, Registration, PlayerTotals, Stadium, Person → Player / Manager / Referee; Annotations allowed on any node (sameAs, source, retrieved) |
match | event | Match, Score, Lineup, Appearance, MatchEvent → Goal / Card / Substitution; status, period, goal and card enums |
table | projection | Standing: every column derived from finished matches |
premier-league | competition | Premier League rules: tie-break order, match, squad and season rules |
catalogue | catalogue | Dataset: who publishes the data, on what terms, and a link to every season and any other documents |
forecast | forecast | ForecastModel, Rating, MatchForecast (with GoalLines and ScoreChances), SeasonProjection; ForecastRules. Scored once played (/logLoss, /rps) |
Another league reuses core, match and table and adds its own rules module.
Generated from the schema by tools/gen-class-diagram.js
(also as class-diagram.svg).
classDiagram
direction TB
class Competition {
+string name
+code country
+CompetitionFormat format
+int? tier
+gYear founded
+int? clubsPerSeason
+int? relegationPlaces
+int? pointsForWin
+int? pointsForDraw
+matchesPerClub() derived
+currentSeason() derived
}
class Season {
+string label
+date startDate
+date endDate
+Club[]? promoted
+date? resultsAsOf
+SeasonCoverage? coverage
+champion() derived
}
class PointsDeduction {
+Club club
+int points
+date? date
+string? reason
}
class Club {
+string name
+string shortName
+code tla
+gYear founded
+string? nickname
+string[]? altNames
+hexColour[]? colours
+KitPattern? kitPattern
}
class Registration {
+Player player
+Season season
+int shirtNumber
+bool homegrown
}
class Stadium {
+string name
+string city
+int? capacity
+decimal? latitude
+decimal? longitude
}
class Person {
<<abstract>>
+string name
+string? knownAs
+date dateOfBirth
+code nationality
+age() derived
}
class Player {
+Position position
+Foot preferredFoot
}
class Manager {
+Club? club
}
class Referee {
+bool fifaBadge
}
class TableZone {
+int from
+int to
+ZoneKind kind
}
class Match {
+dateTime kickoff
+bool? timeConfirmed
+int matchweek
+MatchStatus status
+int? attendance
+Club homeTeam
+Club awayTeam
+Stadium venue
+Referee? referee
+homeScore() derived
+awayScore() derived
+result() derived
+halfTimeScore() derived
}
class Lineup {
+Club club
+string formation
+Manager manager
}
class Appearance {
+Player player
+int shirtNumber
+bool starter
+bool captain
+minutesPlayed() derived
}
class MatchEvent {
<<abstract>>
+int minute
+int? addedTime
+Period period
+Club club
+clock() derived
}
class Goal {
+Player scorer
+Player? assist
+GoalKind kind
+creditedTo() derived
}
class Card {
+Person player
+CardColour colour
}
class Substitution {
+Player playerOff
+Player playerOn
+bool concussion
}
class Score {
+int home
+int away
}
class Standing {
+Club club
+Season season
+played() derived
+won() derived
+drawn() derived
+lost() derived
+goalsFor() derived
+goalsAgainst() derived
+goalDifference() derived
+points() derived
+deducted() derived
+position() derived
+form() derived
}
class Dataset {
+string name
+string publisher
+iri? license
+string[]? attribution
+dateTime updated
+string schemaVersion
+Competition[]? competitions
+Season[]? seasons
+iri includes
}
class ForecastModel {
+string name
+string? modelVersion
+string? method
}
class Rating {
+Club club
+ForecastModel model
+decimal value
+date asOf
+int? rank
}
class MatchForecast {
+Match fixture
+ForecastModel model
+dateTime issued
+decimal homeWin
+decimal draw
+decimal awayWin
+decimal? expectedHomeGoals
+decimal? expectedAwayGoals
+decimal? bothTeamsScore
+logLoss() derived
+rps() derived
}
class GoalLine {
+decimal line
+decimal over
}
class ScoreChance {
+int home
+int away
+decimal chance
}
class SeasonProjection {
+Club club
+Season season
+ForecastModel model
+dateTime issued
+decimal expectedPoints
+decimal[] positions
+string? scenario
+championChance() derived
+notFinishing() derived
+zoneChance() derived
}
Competition "1" *-- "0..*" TableZone : zones
Competition "1" *-- "1..*" Season : seasons
Season --> "2..*" Club : clubs
Season "1" *-- "0..*" Match : matches
Season "1" *-- "0..*" PointsDeduction : deductions
Season ..> "0..*" Standing : /table
Club --> "1" Stadium : homeGround
Club "1" *-- "0..*" Registration : squad
Person <|-- Player
Person <|-- Manager
Person <|-- Referee
Match "1" *-- "0..2" Lineup : lineups
Match "1" *-- "0..*" MatchEvent : events
Match "1" *-- "0..1" Score : fullTime
Match "1" *-- "0..1" Score : halfTime
Match "1" *-- "0..1" Score : currentScore
Lineup "1" *-- "11..20" Appearance : appearances
MatchEvent <|-- Goal
MatchEvent <|-- Card
MatchEvent <|-- Substitution
MatchForecast "1" *-- "0..*" GoalLine : goalLines
MatchForecast "1" *-- "0..*" ScoreChance : scores
Data in this vocabulary is JSON-LD with this repo's context.jsonld:
{ "@context": "https://football-schema.github.io/schema/context.jsonld",
"@graph": [ { "@id": "#this", "@type": "Club", "name": "Arsenal Football Club", "tla": "ARS", … } ] }
The package exports loaders, the derivations and a validator:
import { loadSchema, loadDir, loadLinked, score, standing, classify } from 'football-schema/model.js';
import { validate } from 'football-schema/validate.js';
// from disk: every file under a directory
const problems = validate(await loadSchema(), await loadDir('data/')); // [] when valid
// from the web: one address, every linked document (seasons -> matches -> clubs -> stadiums)
const g = await loadLinked('https://melvin.me/public/matchday/data/seasons/2026-27.jsonld');
const season = g.nodes.find((n) => n['@type'] === 'Season');
const matches = g.nodes.filter((n) => n['@type'] === 'Match');
const table = classify(season.clubs.map((c) => standing(c, matches, undefined, { deductions: season.deductions })));
validate checks every node against its class, that references resolve to the right types, and the
Premier League's match and season rules (for example a complete double round-robin).
model.js also runs in a browser as it is, with no install or build: import it from this site, and
loadLinked fetches the data (a path is relative to the page; data on another host needs CORS headers).
matchday's viewer is built this way.
<script type="module">
import { loadLinked, standing, classify } from 'https://football-schema.github.io/schema/tools/model.js';
const g = await loadLinked('https://melvin.me/public/matchday/data/seasons/2026-27.jsonld', { follow: ['clubs', 'matches'] });
</script>
Worked examples: 2012-05-13-mci-qpr.jsonld, Manchester City 3–2
QPR recorded as events only (npm run derive computes its score and table);
2023-24-deductions.jsonld, Everton's and Forest's points deductions
with their source and Wikidata identities; 2012-05-13-forecast.jsonld,
an (illustrative) forecast for that MCI–QPR match in another document, scored by forecastScore(); and
dataset.jsonld, a Dataset that links to them.
So that anyone can build on what you publish:
dataset.jsonld at the
data's root, linking every season. A consumer then needs that one address: loadLinked follows the links.seasons/2026-27.jsonld, matches/2026-27/mw08.jsonld,
clubs/ARS.jsonld#this).application/ld+json with Access-Control-Allow-Origin: *, so pages on other sites can read it.source and retrieved on any node, and the Dataset's attribution for
credit lines your sources' terms require.fixture), so anyone
can score them once it is played. Say which model made them.sameAs (their Wikidata entity) and altNames, so other datasets can be joined to
yours without hand-made name tables.Built on it: matchday, a Premier League scores site, and premelo, Elo ratings and predictions for twenty European leagues.
The schema and the package share one version (schemaVersion in a Dataset says which one data conforms
to). Until 1.0: a new version may add classes, fields and enumeration members, all optional, so data that was
valid stays valid; anything removed or renamed is first marked deprecated for at least one version, and the
change is listed below. IRIs (urn:football:…) never change meaning.
model.js runs in the browser as well as Node (the file system is used only in Node). loadLinked keeps up to parallel documents in flight (a pool, not batches; same order of results) and, given onError, skips a document it cannot read and lists it in errors.PlayerTotals
(a player's league goals, matches, assists and penalties for one club in one season, as of a date).
Player.position, Player.preferredFoot, Registration.shirtNumber and Registration.homegrown are
optional, since few sources have them. loadLinked also follows squad and player.forecast module: ForecastModel, Rating, MatchForecast (GoalLine, ScoreChance),
SeasonProjection and ForecastRules (chances 0 to 1 that add up, issued before kick-off); forecastScore(),
zoneChance() and notFinishing() (a projection's places may add up to less than 1, e.g. under an expulsion scenario). Season.coverage (complete or partial; a partial season is exempt from the round-robin
rules). Dataset.includes, and Dataset.seasons may be empty. loadLinked fetches several documents at once.sameAs, source, retrieved. Club.altNames. PointsDeduction
and Season.deductions, counted by standing() (and Standing.deducted). The catalogue module:
Dataset. loadGraph reads over HTTP; loadLinked follows links from one address.npm run diagram # regenerate class-diagram.svg + docs/class-diagram.mmd
npm run derive # derived values for the examples
npm test # schema closure, diagram freshness, examples, derivations
Zero dependencies; Node 20+. index.html is the schema reference, rendered from schema/*.jsonld.
Terms are named in the urn:football: namespace (so Match is urn:football:Match); the context and
this reference are published at https://football-schema.github.io/schema/.