3. Examples

Example 4.1. Using sequence and choice
<command name="addListItem">
  <macro undoable="true">
    <choice>
      <sequence>
        <command name="selectNode" 
                 parameter="ancestor[implicitElement] 
                            {http://www.w3.org/1999/xhtml}ul 
                            {http://www.w3.org/1999/xhtml}ol" />
        <command name="selectNode" parameter="child" />
        <command name="insertNode" parameter="sameElementAfter" />
      </sequence>

      <sequence>
        <choice>
          <sequence>
            <command name="selectNode" 
                     parameter="ancestorOrSelf[implicitElement] 
                                {http://www.w3.org/1999/xhtml}dt" />
            <!-- Assumes that a dt is followed by a dd. -->
            <command name="selectNode" parameter="nextSibling" />
          </sequence>
          <command name="selectNode" 
                   parameter="ancestorOrSelf[implicitElement] 
                              {http://www.w3.org/1999/xhtml}dd" />
        </choice>
        <command name="insert"
                 parameter="after {http://www.w3.org/1999/xhtml}dt" />
        <command name="insert"
                 parameter="after {http://www.w3.org/1999/xhtml}dd" />
        <command name="selectNode" parameter="previousSibling" />
      </sequence>
    </choice>
  </macro>
</command>

In the above example , the macro command addListItem, which is used to add a li to a ul or ol or to add a dt/dd pair to a dl, can be described as follows:

  • Select ancestor ul or ol and then

    • Select previously select child which is always a li when the document is valid.

      (The selectNode command selects all the ancestors one after the other until it reaches the searched ancestor. This is equivalent to interactively typing Ctrl+Up until the desired ancestor is selected.)

    • AND insert element of same type (a new li) after selected element (a li).

  • OR select

    • next sibling of ancestor dt (assumes that a dt is always followed by a dd);

    • OR ancestor dd.

    Then

    • Insert a dt after the selected element (a dd).

    • AND insert a dd after the selected element (the newly inserted dt).

    • AND select previous sibling (the newly inserted dt) of selected element (the newly inserted dd).

Example 4.2. Macro-variables
<command name="convertToLink">
  <macro undoable="true" repeatable="true" label="Convert to &lt;a&gt;">
    <sequence>
      <command name="convert" parameter="{http://www.w3.org/1999/xhtml}a" />
      <command name="putAttribute" parameter="%0 %1" />
    </sequence>
  </macro>
</command>

<binding>
  <keyPressed code="F3" />
  <command name="convertToLink" parameter="href ???" />
</binding>

<binding>
  <keyPressed code="F3" modifiers="shift" />
  <command name="convertToLink" parameter="name XXX" />
</binding>

In the above example, macro-command convertToLink must be passed two arguments which specify which type of XHTML a element is to be created: is it target or is it a link? These arguments are referenced in the parameter of the putAttribute command using variables %0 and %1.

Example 4.3. The "%_" macro-variable
<command name="insertCommandOutput">
  <macro>
    <sequence>
      <command name="run" />
      <command name="insertString" parameter="%_" />
    </sequence>
  </macro>
</command>

In the above example, the output of the external program executed by the run command is referenced in the parameter of the insertString command using the %_ variable. (The run command having no parameter will prompt the user to specify which external program is to be executed.)

Example 4.4. Using the fail construct
<command name="preview">
  <macro>
    <sequence>
      <pass>
        <match context="/*" pattern="html:html" 
               xmlns:html="http://www.w3.org/1999/xhtml" />
        <fail><command name="XXE.save" /></fail>
      </pass>
      <command name="start" parameter="helper(defaultViewer) '%D'" />
    </sequence>
  </macro>
</command>

Start the web browser to preview the current document if it has an html root element and if it does not need to be saved.

Example 4.5. Using the XPath-based constructs match and set
<command name="moveListItemUp">
  <macro undoable="true" label="Move List Item Up">
    <sequence>
      <command name="selectNode" 
        parameter="ancestorOrSelf[implicitElement] listitem callout step" />
      <match context="$selected" pattern="*[position() &gt; 1]" />
      <set variable="anchor" context="$selected" 
           expression="./preceding-sibling::*[1]" />
      <command name="cut" />
      <set variable="selected" expression="$anchor" />
      <command name="paste" parameter="before" />
    </sequence>
  </macro>
</command>

Move a list item up in the list. That is, the preceding sibling of the explicitly or implicitly selected list item becomes its following sibling.

Example 4.6. A contextual drop
<binding>
  <appEvent name="drop" />
  <command name="dropURL" parameter="%{value}" />
</binding>

<command name="dropURL">
  <macro>
    <choice>
      <sequence>
        <match context="$clickedElement" pattern="html:a[@href]" 
               xmlns:html="http://www.w3.org/1999/xhtml" />
        <set variable="selected" expression="$clickedElement" />
        <get expression="relativize-uri('%0')" />
        <command name="putAttribute" parameter="href '%_'" />
        <command name="status" parameter="Changed href."/>
      </sequence>

      <command name="XXE.open" parameter="%0" />
    </choice>
  </macro>
</command>

When a string is dropped on an XHTML <a href="..."> element, this string is assigned to the href attribute (after considering this string as an URL and trying to make it relative to the base URL of the a element). When a string is dropped on any other element, XXE default action is used instead: consider the string as the URL or filename of a document to be opened.

The above macro uses the following XPath extension function: relativize-uri() in XMLmind XML Editor - Support of XPath 1.0.

Example 4.7. Insert nodes copied from another document
<binding>
  <keyPressed code="F7" />
  <command name="insertFromOtherDoc" 
           parameter="into" />
</binding>

<property name="templateFile"
          url="true">VATrates.html</property>

<command name="insertFromOtherDoc">
  <macro>
    <sequence>
      <command name="prompt"
        parameter="Question 
                   'ID of the element to be inserted at¬
caret position (e.g. germany_vat):'" />
      <set variable="elementId" expression="%_"
           plainString="true" />
      <get expression="serialize(document(system-property(¬
'templateFile'))//*[@id=$elementId])"/>
      <command name="paste" parameter="%0 %_" />
    </sequence>
  </macro>
</command>

The nodes are copied from file VATrates.html. Notice how a property configuration element having attribute url=true is used to make sure that the URL of the source document VATrates.html is resolved against the URL of the configuration file containing the macro.

The above macro uses the following XPath extension function: serialize() in XMLmind XML Editor - Support of XPath 1.0.

Example 4.8. Convert a DocBook 5 para to a formalpara
<command name="paraToFormalpara">
  <macro undoable="true"1 label="Para to Formalpara">
    <sequence>
      <command name="selectNode" 
               parameter="ancestorOrSelf[implicitElement] 
                          {http://docbook.org/ns/docbook}para" />2

      <script context="$selectedElement"3><![CDATA[4
        namespace db = "http://docbook.org/ns/docbook";5

        set-variable("formalpara", 
                     <db:formalpara><db:title>TITLE HERE</db:title></db:formalpara>);6
        wrap-element($formalpara);7

        set-variable("script-selected", $formalpara);8
        set-variable("script-dot", ($formalpara//text())[1]);9
      ]]></script>
    </sequence>
  </macro>
</command>

1

Do not forget to specify undoable="true" when your macro contains a script.

2

This makes sure that a para is explicitly selected.

3

The script will not run unless a single element is explicitly selected.

4

The XED source is directly contained in the script element. When this is the case, do not forget to use a CDATA section. An alternative would have been to specify the location of an external XED script using the location attribute of the script element.

5

Declare the DocBook 5 namespace.

Note that the above XED script could also have used a default namespace:

namespace "http://docbook.org/ns/docbook";

set-variable("formalpara", 
             <formalpara><title>TITLE HERE</title></formalpara>);
wrap-element($formalpara);

set-variable("script-selected", $formalpara);
set-variable("script-dot", ($formalpara//text())[1]);

as the default namespace is automatically used by element names, element templates (e.g. <formalpara><title>) and by XPath expressions, but not by attribute names and variable names (e.g. script-dot).

6

Variable formalpara contains an empty formalpara element, specified using an element template. Note that element templates are instantiated verbatim. Therefore do not indent an element template.

Also note that without the "TITLE HERE" placeholder for the text of the title, the formalpara/title element would have been created without the customary empty text() child node, which is valid, but not user-friendly.

7

Equivalent to wrap-element($formalpara, .). This replaces the context node (.), which is selected para, by a formalpara containing selected para.

8

Setting variable script-selected allows to specify the first node of the node selection. Here we want to explicitly select the newly created formalpara.

9

Setting variable script-dot allows to specify the textual node containing the caret (also called "insertion cursor"). Here we want to move the caret inside the newly created formalpara.

Note that the above macro may be implemented much less efficiently by replacing the script child element of macro by the invocation of a process command. See Section 2.1, “Convert explicitly or implicitly selected para to a formalpara.