Connecting Q42's Xopus editor to Lenya

  1. General Information
  2. Xopus requests and responses (the interface)
    1. Open File
    2. Checkin File (and quit Xopus)
    3. Save File (and continue editing)
    4. Spellcheck File
    5. Exception
  3. Navigation Bar and Edit/Open Button
  4. Configuration of requested URL by the client Xopus
  5. Location of Xopus
  6. Setting up the Lenya CMS for Xopus
  7. Hooking Xopus to an existing page
  8. Test Xopus
  1. General Information

    The Xopus Wysiwyg XML Editor allows to edit the content of XML files transparently within the Web browser, without confronting the user with xml/xsl tags. It is currently tested to work with IE 5.5 and IE 6.0.

    Xopus communicates with the http server through a series of requests, and expects the server to return appropriate responses. The structure and content of these requests and responses is defined and explained below. To integrate Xopus into the Cocoon environment, we need to implement an interface to handle those requests.

  2. Xopus requests and responses (the interface)

    The requests Xopus sends to the server and the responses it expects are valid xml streams according to the definitions below.

    1. Opening a file for editing

      Xopus uses 3 requests to get the contents of the corresponding xml, xsl and xsd files for the content to be edited. This file trio follows the well-known MVC (Model-View-Controller) pattern:

      File Type Extension Function
      XML File .xml Model
      Stylesheet .xsl View
      Schema .xsd Controller

      The <request> element has always the attribute type="open", while the <data> elements, which are children of the <request> elements, have the attributes type="xml|xsl|xsd", respectively.

      For each of these requests, Xopus expects the "right" responses from the server. These responses are always enclosed in <response> tags, and should have the same id as the requests, and an attibute status="ok". In case of an error, the status attribute will be set to "error" and return an error message.

      After the formal definition of the "open file" dialog, there is a (still somewhat generic) example to demonstrate the use of this interface.

      Interface definition for the "open file" dialog

      Here, we are defining the xml structure of the dialog between Xopus and the server for opening a file for editing. We have 3 requests, and 3 corresponding responses, that have to be exchanged in this order:

      1. Request for xml file (Xopus to Server)
      2. Response returning xml file (Server to Xopus)
      3. Request for xsl file (Xopus to Server)
      4. Response returning xsl file (Server to Xopus)
      5. Request for xsd file (Xopus to Server)
      6. Response returning xsd file (Server to Xopus)

      The structure of these requests and responses is defined as:

      Request messages (Xopus to Server)
                    
      <request 
          type="open" 
          id="req_path/filename_id">
        <data 
            type="xml|xsl|xsd"                           <!-- One request for each type of data -->
            id=path/filename>
        </data>
      </request>
                    
                  
      Response messages (Server to Xopus)
                    
      <response 
          id="req_path/filename_id"        <!-- Same id as the request -->
          status="ok"                                    <!-- If no error occured -->
          type="open"                                    <!-- Same type as the request -->
          xmlns:xlink="http://www.w3.org/xlink">      <!-- This is probably optional??? -->
        <data 
            id=path/filename                      <!-- Same id as the request -->
            type="xml|xsl|xsd">                       <!-- Same type as the request -->
          Content of path/filename
        </data>
      </response>
                    
                  

      Implementation Example

      When everything goes well, i.e. no errors occur, the exchange between Xopus and the server looks like the following example:

      1. Request 1 (Xopus to Server)
      2. Response 1 (Server to Xopus)
      3. Request 2 (Xopus to Server)
      4. Response 2 (Server to Xopus)
      5. Request 3 (Xopus to Server)
      6. Response 3 (Server to Xopus)

      Xopus (Request 1):

                    
      <request 
          type="open" 
          id="req_somepath/somedoc.xml_someid">
        <data 
            type="xml" 
            id="somepath/somedoc.xml">
        </data>
      </request>
                    
                  

      Server (Response 1):

                    
      <?xml version="1.0" encoding="utf-8"?>        <!-- This is probably not needed -->
      
      <response 
          id="req_somepath/somedoc.xml_someid" 
          status="ok" 
          type="open" 
          xmlns:xlink="http://www.w3.org/xlink">
        <data 
            id="somepath/somedoc.xml" 
            type="xml">
          <Root>             <!-- Start of the requested file's content -->
            ...
            ...
            ...           <!-- Content of the xml file -->
            ...
            ...                
          </Root>            <!-- End of the requested file's content -->
        </data>
      </response>
                    
                  

      Xopus (Request 2):

                    
      <request 
          type="open" 
          id="req_somepath/somestylesheet.xsl_somenewid">
        <data 
            type="xml" 
            id="somepath/somestylesheet.xsl">
        </data>
      </request>
                    
                  

      Server (Response 2):

                    
      <?xml version="1.0" encoding="utf-8"?>        <!-- This is probably not needed -->
      
      <response 
          id="req_somepath/somestylesheet.xsl_somenewid" 
          status="ok" 
          type="open" 
          xmlns:xlink="http://www.w3.org/xlink">
        <data 
            id="somepath/somestylesheet.xsl"
            type="xsl">
          <xsl:stylesheet version="1.0"               <!-- Start of the requested stylesheet's content -->
                             xmlns:xlink="http://www.w3c.org/xlink" 
                             xmlns:xsl="http://www.w3.org/1999/XSL/Transform">             
            ...
            ...
            ...           <!-- Content of the stylesheet -->
            ...
            ...                
          </xsl:stylesheet>            <!-- End of the requested stylesheet's content -->
        </data>
      </response>
                    
                  

      Xopus (Request 3):

                    
      <request type="open" 
               id="req_someschema.xsd_someotherid">
        <data type="xsd" 
              id="someschema.xsd">
        </data>
      </request>
                    
                  

      Server (Response 3):

                    
      <?xml version="1.0" encoding="utf-8"?>        <!-- This is probably not needed -->
      
      <response id="req_someschema.xsd_someotherid" 
                status="ok" 
                type="open" 
                xmlns:xlink="http://www.w3.org/xlink">
        <data id="someschema.xsd" 
              type="xsd">
          <Schema xmlns="urn:schemas-microsoft-com:xml-data" 
                  xmlns:dt="urn:schemas-microsoft-com:datatypes" 
                  xmlns:xlink="http://www.w3c.org/xlink">
            <AttributeType dt:type="string" name="Id"/>
            <AttributeType dt:type="string" name="Name"/>
            <AttributeType default="URL" dt:type="string" name="href"/>
            <ElementType content="eltOnly" model="closed" name="Bericht">
              <group order="seq">
                      <element maxOccurs="1" minOccurs="1" type="Meta"/>
                      <element maxOccurs="1" minOccurs="1" type="Content"/>
                      <element maxOccurs="1" minOccurs="0" type="WeiterfuehrendeLinks"/>
              </group>
            </ElementType>
            <ElementType content="eltOnly" model="closed" name="Meta">
              <group order="seq">
                      <element maxOccurs="1" minOccurs="1" type="ErscheinungsDatum"/>
                      <element maxOccurs="1" minOccurs="1" type="ZeitungsRessort"/>
                      <element maxOccurs="1" minOccurs="1" type="OnlineRessort"/>
              </group>
            </ElementType>
            ...
            ...
            ...           <!-- Further definitions skipped to improve readability -->
            ...
            ...                
          </Schema>
        </data>
      </response>
                    
                  

      Exception Handling

      Error (Request for an xml File):

      When the xml-file is already checked out by another user, the response looks like :

                    
                      <response
                      status="error"
                      xmlns:xlink="http://www.w3.org/xlink">
                        <error
                        number="16">
                          <title>You are not allowed to edit this document right now. </title>
                          <message>"User 'Lala' started working on it on Wed Jun 19 14:22:02 </message>
                        </error>
                      </response>
                    
                  

      Error (Bad data type requested):

      When the data type isn't one of xml, xsl or xsd:

                    
                      <response
                      status="error"
                      xmlns:xlink="http://www.w3.org/xlink">
                        <error
                        number="2">
                          <title>No such Type. </title>
                          <message>data type </message>
                        </error>
                      </response>
                    
                  

      Error (All Requests):

      When the identity of the user isn't defined, the response looks like :

                    
                      <response
                      status="error"
                      xmlns:xlink="http://www.w3.org/xlink">
                        <error
                        number="1">
                          <title>An internal error has occurred: </title>
                          <message>Caught exception in dispatchRequest(): Unable to get identification from session, check cookies and user! </message>
                        </error>
                      </response>
                    
                  

      When we couldn't detemine the filename for request :

                    
                      <response
                      status="error"
                      xmlns:xlink="http://www.w3.org/xlink">
                        <error
                        number="1">
                          <title>An internal error has occurred: </title>
                          <message>Caught exception in dispatchRequest(): Unable to determine filename for request </message>
                        </error>
                      </response>
                                                                                                                                           
                  

      When the file doesn't exist:

                    
                      <response
                      status="error"
                      xmlns:xlink="http://www.w3.org/xlink">
                        <error
                        number="4">
                          <title>No such File. </title>
                          <message>file </message>
                        </error>
                      </response>
                    
                  

      An other error occurs

                    
                      <response
                      status="error"
                      xmlns:xlink="http://www.w3.org/xlink">
                        <error
                        number="3">
                          <title> File file exists, but an internal error occured. </title>
                          <message>exception message </message>
                        </error>
                      </response>
                    
                  
    2. Checking in the file when finished editing

      At the end of the editing session, when the user clicks on "close", Xopus places a single request containing the new contents of the edited xml file. As the stylesheet and the schema are not modified during editing, there are no requests for the updating of these.

      Again, here is the interface definition and an example for the implementation.

      Interface definition for the "checkin file" dialog

      Request message (Xopus to Server)

                    
      <request 
          type="checkin" 
          id="req_path/filename_id">
        <data 
            type="xml"                           <!-- Only xml file is checked back in -->
            id=path/filename>
          Content of the editor (current state of path/filename)
        </data>
      </request>
                    
                  

      Response message (Server to Xopus)

                    
      <response 
          id="req_path/filename_id"        <!-- Same id as the request -->
          status="ok"                                    <!-- If no error occured -->
          type="checkin"                                 <!-- Same type as the request -->
          xmlns:xlink="http://www.w3.org/xlink">      <!-- This is probably optional??? -->
        <data 
            id=path/filename                      <!-- Same id as the request -->
            type="xml">                               <!-- Same type as the request -->
          Content of path/filename
        </data>
      </response>
                    
                  

      Implementation Example

      When everything goes well, i.e. no errors occur, the exchange between Xopus and the server looks like the following example:

      Xopus (Request):

                    
      <request type="checkin" 
               id="req_2002/01/17/al/newzzCWKQDEV5-12.nzzoml_1014216332805">
        <data type="xml" 
              id="2002/01/17/al/newzzCWKQDEV5-12.nzzoml">
          <Bericht Id="newzz-2002.01.17-al-newzzCWKQDEV5-12">
            <id>2002/01/17/al/newzzCWKQDEV5-12</id>
            <Meta>
              <ErscheinungsDatum>
                <Jahr>2002</Jahr>
                ---- snip ----
              </ErscheinungsDatum>
              ---- snip ----
            </Meta>
            <Content>
            ---- snip ----
            </Content>
            ---- snip ----
          </Bericht>
        </data>
      </request>
                    
                  

      Server (Response):

                    
      <response id="req_2002/01/17/al/newzzCWKQDEV5-12.nzzoml_1014216332805" 
                status="ok" 
                type="checkin" 
                xmlns:xlink="http://www.w3.org/xlink">
        <data id="2002/01/17/al/newzzCWKQDEV5-12.nzzoml" 
              type="xml">
          <Bericht Id="newzz-2002.01.17-al-newzzCWKQDEV5-12">
            <id>2002/01/17/al/newzzCWKQDEV5-12</id>
            <Meta>
              <ErscheinungsDatum>
                <Jahr>2002</Jahr>
                ---- snip ----
              </ErscheinungsDatum>
              ---- snip ----
            </Meta>
            <Content>
            ---- snip ----
            </Content>
            ---- snip ----
          </Bericht>
        </data>
      </response>
                    
                  

      Exception Handling

      When the file couldn't be checked in because user Lala already checked out the document, the response looks like :

                    
                      <response 
                      status="error"
                      xmlns:xlink="http://www.w3.org/xlink">
                        <error
                        number="17">
                          <title>You are not allowed to check in this document. </title>
                          <message>"There was a checkout by user 'Lala' at Wed Jun 19 14:22:02 </message>
                        </error>
                      </response>
                    
                  

      When the identity of the user isn't defined, the response looks like :

                    
                      <response
                      status="error"
                      xmlns:xlink="http://www.w3.org/xlink">
                        <error
                        number="1">
                          <title>An internal error has occurred: </title>
                          <message>Caught exception in dispatchRequest(): Unable to get identification from session, check cookies and user! </message>
                        </error>
                      </response>
                    
                  

      When we couldn't detemine the filename for request :

                    
                      <response
                      status="error"
                      xmlns:xlink="http://www.w3.org/xlink">
                        <error
                        number="1">
                          <title>An internal error has occurred: </title>
                          <message>Caught exception in dispatchRequest(): Unable to determine filename for request </message>
                        </error>
                      </response>
                    
                  
    3. Save file temporarily while continuing editing

      This request/response pair performs a temporary save of the file being edited. From the interface point of view, the only difference to the "checkin" transaction is the type attribute, which is set to type="save".

      Interface definition for the "save file" dialog

      Request message (Xopus to Server)

                    
      <request 
          type="save" 
          id="req_path/filename_id">
        <data 
            type="xml"                           <!-- Only xml file is saved -->
            id=path/filename>
          Content of the editor (current state of path/filename)
        </data>
      </request>
                    
                  

      Response message (Server to Xopus)

                    
      <response 
          id="req_path/filename_id"        <!-- Same id as the request -->
          status="ok"                                    <!-- If no error occured -->
          type="save"                                    <!-- Same type as the request -->
          xmlns:xlink="http://www.w3.org/xlink">      <!-- This is probably optional??? -->
        <data 
            id=path/filename                      <!-- Same id as the request -->
            type="xml">                               <!-- Same type as the request -->
          Content of path/filename
        </data>
      </response>
                    
                  

      Exception Handling

      When we couldn't write the file :

                    
                      <response
                      status="error"
                      xmlns:xlink="http://www.w3.org/xlink">
                        <error
                        number="1">
                          <title>An internal error has occurred: </title>
                          <message>Caught exception in dispatchRequest(): Unable to write to output file </message>
                        </error>
                      </response>
                    
                  

      When the file hasn't a root element:

                    
                      <response
                      status="error"
                      xmlns:xlink="http://www.w3.org/xlink">
                        <error
                        number="1">
                          <title>An internal error has occurred: </title>
                          <message>Caught exception in dispatchRequest(): data node does not contain an element node </message>
                        </error>
                      </response>
                    
                  

      When we couldn't detemine the filename for request :

                    
                      <response
                      status="error"
                      xmlns:xlink="http://www.w3.org/xlink">
                        <error
                        number="1">
                          <title>An internal error has occurred: </title>
                          <message>Caught exception in dispatchRequest(): Unable to determine filename for request </message>
                        </error>
                      </response>
                    
                  
    4. Have the content spellchecked while continuing editing

      This request/response pair performs a spellcheck of the file being edited. For this transaction, the type attribute is set to type="checkspelling", and the misspelled words are surrounded by <span class="spell_error_xopus"> </span> tags in the server's response (see example below.

      Interface definition for the "spellcheck file" dialog

      Request message (Xopus to Server)

                    
      <request 
          type="checkspelling" 
          id="req_path/filename_id">
        <data 
            type="xml"
            id=path/filename>
          Content of the editor (current state of path/filename)
        </data>
      </request>
                    
                  

      Response message (Server to Xopus)

                    
      <response 
          id="req_path/filename_id"        <!-- Same id as the request -->
          status="ok"                                    <!-- If no error occured -->
          type="checkspelling"                                    <!-- Same type as the request -->
          xmlns:xlink="http://www.w3.org/xlink">      <!-- This is probably optional??? -->
        <data 
            id=path/filename                      <!-- Same id as the request -->
            type="xml">                               <!-- Same type as the request -->
          Content of the editor (misspelled words tagged)
        </data>
      </response>
                    
                  

      Implementation example

      When everything goes well, i.e. no errors occur, the exchange between Xopus and the server looks like the following example:

      Xopus (Request):

                    
      <request type="checkspelling" 
               id="req_2002/01/17/al/newzzCWKQDEV5-12.nzzoml_1014220920281">
        <data type="xml" 
              id="2002/01/17/al/newzzCWKQDEV5-12.nzzoml">
          <Bericht xmlns:xlink="http:/www.w3.org/xlink" 
                   Id="newzz-2002.01.17-al-newzzCWKQDEV5-12">
            <id>2002/01/17/al/newzzCWKQDEV5-12</id>
            ---- snip ----
            <Content>
              <Head>
                <Haupttitel>Hallo Herr Korosec</Haupttitel>
                <Untertitel>Geaenderter Untertitel</Untertitel>
                <Lead>Geaenderter Lead</Lead>
                <Meta>
                  <Stichwort>ETH</Stichwort>
                  <Autor>lenya</Autor>
                  ---- snip ----
                </Meta>
              </Head>
              <Text>
                <Paragraph>
                  <Subparagraph>Absatz geaendert von Memo</Subparagraph>
                </Paragraph>
                ---- snip ----
              </Text>
              ---- snip ----
            </Content>
          </Bericht>
        </data>
      </request>
                    
                  

      Server (Response):

                    
      <response id="req_2002/01/17/al/newzzCWKQDEV5-12.nzzoml_1014220920281" 
                status="ok" 
                type="checkspelling" 
                xmlns:xlink="http://www.w3.org/xlink">
        <data id="2002/01/17/al/newzzCWKQDEV5-12.nzzoml" 
              type="xml">
          <Bericht Id="newzz-2002.01.17-al-newzzCWKQDEV5-12" 
                   xmlns:xlink="http:/www.w3.org/xlink">
            <id>2002/01/17/al/newzzCWKQDEV5-12</id>
            ---- snip ----
            <Content xmlns:xlink="http://www.w3.org/xlink">
              <Head>
                <Haupttitel>Hallo Herr <span class="spell_error_xopus">Korosec</span></Haupttitel>
                <Untertitel><span class="spell_error_xopus">Geaenderter</span> Untertitel</Untertitel>
                <Lead><span class="spell_error_xopus">Geaenderter</span> Lead</Lead>
                <Meta>
                  <Stichwort>ETH</Stichwort>
                  <Autor>lenya</Autor>
                  ---- snip ----
                </Meta>
              </Head>
              <Text>
                <Paragraph>
                  <Subparagraph>Absatz <span class="spell_error_xopus">geaendert</span> von Memo</Subparagraph>
                </Paragraph>
                ---- snip ----
              </Text>
              ---- snip ----
            </Content>
          </Bericht>
        </data>
      </response>
                    
                  

      Exception Handling

      When no spell checker is defined :

                    
                      <response
                      status="error"
                      xmlns:xlink="http://www.w3.org/xlink">
                        <error
                        number="1">
                          <title>An internal error has occurred: </title>
                          <message>Caught exception in dispatchRequest(): Spell check request received, but there is no spell checker defined </message>
                        </error>
                      </response>
                    
                  
    5. Exception handling

      When the request type is unknown, the response looks like:

                    
                      <response
                      status="error"
                      xmlns:xlink="http://www.w3.org/xlink">
                        <error
                        number="5">
                          <title>The client sent an unknown request type. </title>
                          <message> </message>
                        </error>
                      </response>
                    
                  

      When an other exception occurs, the response looks like:

                    
                      <response
                      status="error"
                      xmlns:xlink="http://www.w3.org/xlink">
                        <error
                        number="1">
                          <title>An internal error has occurred: </title>
                          <message>Caught exception in dispatchRequest(): error message </message>
                        </error>
                      </response>
                    
                  
  3. Navigation Bar and Edit/Open Button

    The Xopus navigation bar can be modified by editing the stylesheet xopus.xsl (Currently located at resources/html/scratchpad/xopus/stylesheets). The Edit/Open Button can be modified by editing the Javascript function createEditButton within the script PREFIX/tomcat/webapps/ROOT/xps/xopus/init.js.
  4. Location of Xopus

    Because Xopus is not Open Source yet, you won't find it within the snapshot or CVS. You will have to ask Q42 to receive a version. If you have a version, then you have to place it within the ROOT directory of Tomcat, i.e. PREFIX/tomcat/webapps/ROOT/xps/xopus.
  5. Configuration of requested URL by the client Xopus

    The requested URL is configured within two files:
    PREFIX/tomcat/webapps/ROOT/xps/xopus/init.js
    PREFIX/tomcat/webapps/ROOT/xps/xopus/logic/index.js

    For the time being it is /lenya/ethz-mat/xopus/XopusInterface

  6. Setting up the Lenya CMS for Xopus

    1. Route all Xopus requests to the handler

      For this purpose, we are sending all requests matching "xopus/**" to a subsitemap, called xopus.xmap, where they are first routed through an action, the XopusHandlerAction.

    2. Handle the requests

      The handler is responsible for decoding the attributes of the request and supplying them to the sitemap, and for handling file operations (i.e. saving), when needed. Check out the source code for more info.

    3. Provide the responses to Xopus

      Using the request parameters (supplied by the handler), the response to Xopus is formatted through a generic stylesheet, xopus_resp.xsl.

  7. Hooking Xopus to an existing page

    To make a page of a publication available for editing with Xopus, follow the example of the Department page of the ETHZ-Mat publication:

    1. Create main_xopus.xsl

      Make a copy of the existing main.xsl and change the include statement for root.xsl to root_xopus.xsl.

    2. Edit the authoring (protected) sitemap

      Change the authoring stylesheet for the page to another version. Don't forget to check for the browser first, Xopus works only with IE 5.5 or later!

      For an example, look at the Department Authoring snippet, where the stylesheets/ethz/mat/Department/authoring/main.xsl stylesheet is replaced by stylesheets/ethz/mat/Department/authoring/main_xopus.xsl.

    3. Edit body.xsl

      Add the call to Xopus to the element of the page that you want to edit. The easiest way to do this is to enwrap the portion that you want to make editable in a <div ...>...</div> statement containing the specific attributes to call Xopus. For example:

                    
      <div id_xopus="dept" 
              xml_xopus="index.xml" 
              xsl_xopus="Department/Edit/xopus.xsl" 
              xsd_xopus="department.xsd">
        <span class="CONTALBLETITLE">Chairman</span>
        <table border="1" cellspacing="0" cellpadding="2">
          <tr>
            <td><a class="CONTABLELINK" href="">Department</a></td>
            <td><a class="CONTABLELINK" href="mailto:{chairman/email}"><xsl:value-of select="chairman/name"/></a></td>
            <td><a class="CONTABLELINK" href="mailto:{chairman/email}"><xsl:value-of select="chairman/email"/></a></td>
          </tr>
        </table>
      </div>
                    
                  

      The file paths must be relative to the "root paths" for each filetype, as defined in the xopus.xmap for the xopushandler. Also, do not use template calls in this stylesheet, as Xopus does not seem to handle those well.

    4. Create the schema

      For an example, see config/doctypes/schemas/department.xsd.