Is there an (already existing) up to date XSD for MUSHclient MCL files/plugin files? I'd be happy to make one if people are interested, I just am uncertain how to verify that it's correct other than perhaps submitting it here as well as testing it against existing MCL/XML files. This might be a pretty niche use-case so for all I know one doesn't exist. Thought I would ask though!
XML schema for MCL/XML files (worlds, plugins)?
Posted by Draeand on Mon 22 Jul 2024 02:45 AM — 7 posts, 13,237 views.
No, there isn't. I must admit that writing XML schemas is not one of my strengths.
I'm not totally sure what a schema is, except to guess that you validate the XML against a schema in order to determine whether it conforms to specifications (eg. a field which should contain a number actually contains a number).
What would the use of it be? Perhaps, if you are hand-writing a plugin you might want to make sure that the fields in the XML will be correctly processed?
You can probably get a good idea of the element names from: https://github.com/nickgammon/mushclient/blob/master/xml/xml_load_world.cpp
The options in the world file are validated against a table here: https://github.com/nickgammon/mushclient/blob/master/scriptingoptions.cpp
That would be a good place to see the allowable ranges for various elements.
For example:
So the element spam_line_count is a number, and its allowable range is 5 to 500.
I'm not totally sure what a schema is, except to guess that you validate the XML against a schema in order to determine whether it conforms to specifications (eg. a field which should contain a number actually contains a number).
What would the use of it be? Perhaps, if you are hand-writing a plugin you might want to make sure that the fields in the XML will be correctly processed?
You can probably get a good idea of the element names from: https://github.com/nickgammon/mushclient/blob/master/xml/xml_load_world.cpp
The options in the world file are validated against a table here: https://github.com/nickgammon/mushclient/blob/master/scriptingoptions.cpp
That would be a good place to see the allowable ranges for various elements.
For example:
{"spam_line_count", 20, O(m_iSpamLineCount), 5, 500 },
{"speed_walk_delay", 0, O(m_iSpeedWalkDelay), 0, 30000, OPT_FIX_SPEEDWALK_DELAY},
So the element spam_line_count is a number, and its allowable range is 5 to 500.
Nick Gammon said:
No, there isn't. I must admit that writing XML schemas is not one of my strengths.
I'm not totally sure what a schema is, except to guess that you validate the XML against a schema in order to determine whether it conforms to specifications (eg. a field which should contain a number actually contains a number).
What would the use of it be? Perhaps, if you are hand-writing a plugin you might want to make sure that the fields in the XML will be correctly processed?
You can probably get a good idea of the element names from: https://github.com/nickgammon/mushclient/blob/master/xml/xml_load_world.cpp
The options in the world file are validated against a table here: https://github.com/nickgammon/mushclient/blob/master/scriptingoptions.cpp
That would be a good place to see the allowable ranges for various elements.
For example:
So the element spam_line_count is a number, and its allowable range is 5 to 500.
No, there isn't. I must admit that writing XML schemas is not one of my strengths.
I'm not totally sure what a schema is, except to guess that you validate the XML against a schema in order to determine whether it conforms to specifications (eg. a field which should contain a number actually contains a number).
What would the use of it be? Perhaps, if you are hand-writing a plugin you might want to make sure that the fields in the XML will be correctly processed?
You can probably get a good idea of the element names from: https://github.com/nickgammon/mushclient/blob/master/xml/xml_load_world.cpp
The options in the world file are validated against a table here: https://github.com/nickgammon/mushclient/blob/master/scriptingoptions.cpp
That would be a good place to see the allowable ranges for various elements.
For example:
{"spam_line_count", 20, O(m_iSpamLineCount), 5, 500 },
{"speed_walk_delay", 0, O(m_iSpeedWalkDelay), 0, 30000, OPT_FIX_SPEEDWALK_DELAY},
So the element spam_line_count is a number, and its allowable range is 5 to 500.
Basically, a schema describes the structure of a document. It not only specifies the elements and attributes of the document but can also specify things like the number of occurrences of an attribute or element, the minimum and maximum of the element, a pattern to verify/validate that element, etc. And though they can be used for validation, you can also pass them to something like CodeSynthesis XSD to generate serialization/deserialization code from them.
There are two ways I know of to write schemas. One way is to use XML itself, although this is annoying and cumbersome, or you can use something like RelaxNG. As an example, I've tried to whip up a basic schema of all the possible elements/attributes, so using RelaxNG's compact representation, I can do something like:
muclient = element muclient {
plugin?,
include_*,
world?,
triggers?,
aliases?,
timers?,
macros?,
variables?,
colours?,
keypad?,
printing?
}
world = element world {
attribute world_file_version { xsd:long }?,
attribute muclient_version { xsd:token }?,
attribute date_saved { xsd:date }?,
attribute accept_chat_connections { xsd:boolean }?,
attribute alternative_inverse { xsd:boolean }?,
attribute alt_arrow_recalls_partial { xsd:boolean }?,
# ...
The '?' in the above means optional (zero or one), the '*' means zero or more. If I had wanted to make one of these required, I would omit either a '*' or '?'. ("include" is a keyword in RelaxNG's compact form, hence the _ after it.) The "attribute" part is split into two parts: the name and the type. So
attribute world_file_version { xsd:long }?,I've already drafted a basic schema for the format, both because I'm working on a project of my own but in case someone else wants it. I'm just uncertain if I've made elements required that shouldn't be required, or optional where they should be required, little things like that; looking through the code makes it difficult to tell what's required and what isn't, so I've just opted for the safest rout (assume that pretty much everything can be optional, worry about that not being the case later). It makes the code a bit annoying to use, but the generate code lets me do something like:
#include "mushclient.h" // mushclient.h is the schema file, can obviously rename it
#include <format>
#include <iostream>
// Assume we've already read the file into an istream called input_stream
// Parse it
const auto doc = muclient_(input_stream);
if (!doc) {
// Parse failed
}
// Now, we can access the world:
const auto world = doc->world();
if (!world) { // world isn't present
// Do something
}
const auto name = world->name(); // This is probably required, so I should make it so
std::cout << std::format("World name is {}\n", name);
For each attribute in the schema, the code generator generates a few methods: two for retrieving the attribute (one read-only, one read-write), and up to three setters (two make copies, one doesn't, and for optional attributes, one of those setters takes an std::optional<T> as a parameter, and only sets it if the optional isn't std::nullopt). So not only can you parse your documents but you can also build them from the ground up and serialize them.
That looks nice. Well if you want to put a Github link to your schema we could play with it.
My schema is here, both in RelaxNG's compact format (RNC) and as an XML schema definition: https://github.com/ethindp/mushclient-schemas
I have managed to get it successfully validating with world files with Jing, but I'm still trying to get plugins to validate. Jing is being overly strict with whitespace, so I'm trying to resolve that problem, as well as a couple other issues with things like the `date-written` attribute, which looks like it'd fit `xsd:dateTime` but it isn't validating. I feel like an (excellent) test-suite for this in the future could probably be running a validator over the entire plugins directory of a MUSHclient install as well as some test worlds from simple to very complex worlds as a starting point, but that's for later.
I have managed to get it successfully validating with world files with Jing, but I'm still trying to get plugins to validate. Jing is being overly strict with whitespace, so I'm trying to resolve that problem, as well as a couple other issues with things like the `date-written` attribute, which looks like it'd fit `xsd:dateTime` but it isn't validating. I feel like an (excellent) test-suite for this in the future could probably be running a validator over the entire plugins directory of a MUSHclient install as well as some test worlds from simple to very complex worlds as a starting point, but that's for later.
You should probably make the world name, IP address (site) and port number required fields, as the client won't let you view other configuration tabs until they are filled in.
Done! :) I also made id required since I assume the client will auto-generate that, so it being empty would be really odd.