Skip to content

Notes on Using Blockly and its XML

Reinhard Budde edited this page Dec 8, 2020 · 1 revision

Blockly and XML and the AST

We start with a blockly code snippet, that adds 1 and 2 and stores the result in x. This is the result of the user's work with the browser-based front-end. Blockly handles all user actions.

XML

Now the user clicks the show code button. Blockly generates a XML representation of the graphical program. Our code snipped is represented as:

<block type="variables_set" id="b|fRG]X]?T;L=467q;dp" intask="true">
    <mutation datatype="Number"/>
    <field name="VAR">x</field>
    <value name="VALUE">
        <block type="math_arithmetic" id="3SQf4D5*xXxH%iAR:@;3" intask="true">
            <field name="OP">ADD</field>
            <value name="A">
                <block type="math_number" id="kp`TFdz?,*z}t!dd_4!J" intask="true">
                    <field name="NUM">1</field>
                </block>
            </value>
            <value name="B">
                <block type="math_number" id="nL4n}Uj(OK%d14@UB:2V" intask="true">
                    <field name="NUM">2</field>
                </block>
            </value>
        </block>
    </value>
</block>

The XML is stored into a JSON object and send from the browser to a REST-endpoint of the server. From here everything is done with Java.

We transform the XML to an AST (abstract syntay tree), which is more adequate for further processing (i.e. code generation). This is done in two steps:

  • XML to Jaxb generated beans (this is described below in detail, but it is a simple, fully automated job). The Jaxb framework generates everything needed.
  • Jaxb generated beans to AST. This is facilitated by the factory method jaxbToAst, which is availabe from all the classes, that can be part of the AST (these are always subclasses of class Phrase<V>.

JAXB

XML is not nice to process and furthermore XML should be validated w.r.t. a schema. The XML, which Blockly generates, matches the schema defined in OpenRobertaRobot/src/main/resources/blockly.xsd. It is common to use the JAXB framework to process XML input and to use a JAXB tool to generate beans for the XML elements. This is done with maven at compile time. You'll find the generated classes in OpenRobertaRobot/target/generated-sources/jaxb/blockly/de/fhg/iais/roberta/blockly/generated.

For unit test there exist a lot of helper classes (whose names follow the pattern *Helper*ForXmlTest), which show, how the transformation with these generated classes is done programmatically. The basis of the transformation is class JaxbHelper:

  • it takes the blockly.xsd to generate two static objects: the schema object blockSetSchema and the jaxb context object jaxbContext. Note, that objects of class BlockSet are the root of transformed XML.
  • method BlockSet xml2BlockSet(String blocklyXml) of class JaxbHelper creates an unmarshaller (i.e. an transformer from XML to beans), sets the schema, starts the transformation and returns the BlockSet object representing the transformed XML.

The bean returned is structurally equivalent to the XML. For instance, the XML element statement contains an unlimited number of sub-elements, which are blocks, the generated class Statement contains a getter getBlock(), which returns a List<Block> . To tell it again: JAXB generates another representation, which is much easier to process than a XML string, containing every detail from the XML. This is effected without any implementation by the framework.

AST

The JAXB-based tree is then transformed to the AST, which is well suited for analysis and code generation. One nasty thing is, that some information from blockly must be saved into each AST-object. This is needed (in case of user errors, e.g.) to create feedback for the user, because we want to show the feedback attached to the graphical blocks the user had created. Thus an object of class BlocklyBlockProperties is stored in each AST-object exactly for that purpose.

The AST of the expression 1+2 is shown below. Green is the top-level object for the binary op. It contains three beans for the left and right operand and for the operation ADD. These are coloured orange. Each of these sub-beans contain a concrete value, the numeric constant resp. the operator name. These values are coloured yellow. Expression can be nested to any depth required, of course. The AST can be checked for consistency, analysed and used for code generation.

Live View

Have a look at the unit test Expr1add2Test in project RobotMbed and you can follow each step described above in detail by stepping through the test code with an IDE debugger. The RobotMbed project was chosen to have access to a concrete code generator. The CalliopeCppVisitor is used, which generates C++ code.

blocks change their port dynamically according to the changed port in configuration block

  • when writing an action block (robActions.js) in order to make it change the port dynamically add the following lines to the init function of the block:
var ports = getConfigPorts('conf_block_title_in_lower_case');
        this.dependConfig = {
            'type' : 'conf_block_title_in_lower_case',
            'dropDown' : ports
        };

conf_block_title_in_lower_case can be found in the configuration block definition (robConfigDefinitions.js) as property 'title', just put it in lower case.

For example:

confBlocks.plotting = {}
confBlocks.plotting.sensebox = {
    title : 'PLOTTING',

here the title is PLOTTING, so to make the plot_point block dynamically update the port the following is needed:

Blockly.Blocks['robActions_plot_point'] = {
    init : function() {
        this.setColour(Blockly.CAT_ACTION_RGB);
        var dropDownPorts = getConfigPorts('plotting');
        this.dependConfig = {
            'type' : 'plotting',
            'dropDown' : dropDownPorts
        };
Clone this wiki locally