Thursday, August 27, 2015

DITA 1.3 Implementation Status in upcoming Oxygen XML Editor 17.1

Share to Facebook Share to Twitter Email This Share on Google Plus Share on Tumblr

We plan to release Oxygen 17.1 in about a month or two, probably at the beginning of October this year. Starting with version 17.1, Oxygen includes experimental support for editing and publishing using some of the DITA 1.3 features. If you want to test this support and give us feedback please contact us directly to obtain an Oxygen 17.1 beta kit.

To enable DITA 1.3 editing support in Oxygen 17.1 and use the custom bundled DITA Open Toolkit 2.1 for publishing, open the Preferences dialog box, go to DITA, and select the Built-in DITA OT 2.x radio button.

The following table is a list of DITA 1.3 features and their implementation status:

DITA 1.3 Features Implementation Status
Feature Editing Publishing [Latest DITA Open Toolkit 2.x is used.]
DITA 1.3 DTD, XML Schema, and Relax NG-based maps/topics/tasks/references, etc.

New DITA 1.3 file templates. Also by default DITA topics and maps which do not specify version in the DOCTYPE declaration are also considered to be DITA 1.3.

Specific annotations presented in the content completion window and documentation tooltips for all new DITA 1.3 elements.

See below
Learning Object and Group maps New file templates No specific support implemented
Troubleshooting specialization Create and edit new troubleshooting topics No specific support implemented
XML markup domain Validation and Content Completion Special rendering in PDF and XHTML-based outputs.
Equation and MathML domain

Validation and content completion

Display and Insert equations

Special rendering in PDF and XHTML-based outputs.
SVG domain

Validation and content completion

Display referenced SVG content

Special rendering in PDF and XHTML-based outputs.
Other new DITA 1.3 elements (div, strike-through, overline, etc) Validation and Content Completion. Special rendering in PDF and XHTML-based outputs.
Release management domain Validation and Content Completion No specific support implemented.
Scoped keys

Define key scopes

Validate and check for completeness

Resolve keyrefs and conkeyrefs taking key scopes into account.

Partially implemented. Various issues may still be encountered.
Branch filtering Display, create and edit ditavalref elements. Partially implemented. Various issues may still be encountered.
Shorthand to address syntax that identifies elements in the same topic Properly resolved for validation, links, and conrefs. Implemented.
Various table attributes (orientation, rotation, scope, and headers on cells) Not implemented in the Table Properties action support. But attributes can be changed from the Attributes view. Not implemented.
New Map topicref attributes (cascade, deliveryTarget) Allow setting new attributes, propose proper values for them. Implemented.

Monday, August 24, 2015

DITA 1.3 Key Scopes - Next Generation of Reuse

Share to Facebook Share to Twitter Email This Share on Google Plus Share on Tumblr

Thanks to the hard working OASIS DITA TC Group the DITA 1.3 standard is quite close to being released. Oxygen 17.1 which will be released probably in September this year will have experimental DITA 1.3 support. This will include publishing using a custom build of the latest DITA Open Toolkit 2.x engine in which the main developer Jarno Elovirta has already added incipient support for key scopes and branch filtering.

In this blog post I'm going to give you a small example of how key scopes can benefit simple cases of reuse which could not be done previously.

Let's say you have a simple DITA task in which you have described how a certain task can be performed for a certain product. In our case, the task describes peeling a potato:

The task works and at some point in your Vegetables Soup publication you realise you need to write a similar task about peeling cucumbers. The task is exactly the same, except the product name. So naturally you want to reuse the existing written task. For this we re-write the task so that instead of of the product potatoes it contains a key reference:
<ph keyref="vegetable"/>
Next we need to define in our DITA Map the vegetable key and bind it to a specific value in the potatoes context:
 <topicref href="potatoes_overview.dita" keyscope="potatoes">
  <!-- Define the vegetable key value in this key scope -->
  <keydef keys="vegetable">
   <topicmeta>
    <keywords>
     <keyword>potatoes</keyword>
    </keywords>
   </topicmeta>
  </keydef>
  <!-- Reference to the common task -->
  <topicref href="peeling.dita"/>
 </topicref>
and add in our DITA Map another key scope with the overview and the task which deal with cucumbers peeling:
 <topicref href="cucumbers_overview.dita" keyscope="cucumbers">
  <!-- Define the vegetable key value in this key scope -->
  <keydef keys="vegetable">
   <topicmeta>
    <keywords>
     <keyword>cucumbers</keyword>
    </keywords>
   </topicmeta>
  </keydef>
  <!-- Reference to the common task -->
  <topicref href="peeling.dita"/>
 </topicref>
As you may have noticed, we have not used the key scope names for anything. Just by defining the key scopes, we made the product name to be expanded differently in both contexts. But our Vegetables Soup publication may also contain a topic which lists all possible vegetables. This topic is defined in a context outside any key scope:
<topicref href="vegetables_over.dita"/>
and this overview topic can refer to each product name using the full keyscope key reference value:
<!DOCTYPE topic PUBLIC "-//OASIS//DTD DITA Topic//EN" "topic.dtd">
<topic id="vegetables_over">
  <title>Vegetables Overview</title>
  <body>
    <p>This is an overview of all vegetables necessary to make soup. You will learn how to use
      vegetables like <ph keyref="potatoes.vegetable"/> and <ph keyref="cucumbers.vegetable"/> to
      make a great starter soup.</p>
  </body>
</topic>

As stated before, this kind of reuse was not possible using the standard DITA 1.2 standard constructs. As it turns out, with DITA 1.3 we can also implement this kind of reuse using branch filtering. The DITA samples for this post can be downloaded from http://www.oxygenxml.com/forum/files/keyscopesBlogSamples.zip.

As usual any feedback is welcomed.

If you would like to beta test Oxygen XML Editor 17.1 with experimental DITA 1.3 support please contact us to support@oxygenxml.com.

Wednesday, August 12, 2015

Document Type Extension Sharing

Share to Facebook Share to Twitter Email This Share on Google Plus Share on Tumblr

You can extend a default bundled document type (like DITA or Docbook) in the Document Type Association preferences page, make modifications and then share the extension with your team.

The steps below describe how an extension of the DITA framework which removes certain elements from the content completion list can be constructed and shared:
  1. Create somewhere on your disk, in a place where you have full write access a folder structure like: custom_frameworks/dita-extension.
  2. In the Document Type Association / Locations preferences page add in your Additional frameworks directories list the path to your custom_frameworks folder.
  3. In the Document Type Association preferences page select the DITA document type configuration and use the Extend button to create an extension for it.
  4. Give a custom name to the extension, for example DITA - Custom and then change its Storage to external, then save it to a path like: path/to/.../custom_frameworks/dita-extension/dita-extension.framework.
  5. Make changes to the extension, for example go to the Author->Content completion tab and add in the Filter - Remove content completion items list elements which should not be presented to the end users.
  6. Click OK to close the dialog and then either OK or Apply to save the preferences changes.

After you perform the steps above you will have in the dita-extension folder a fully functioning framework which can be shared with others.

The framework can then be shared with others in several ways:
  • Copy it to their [OXYGEN_DIR]/frameworks directory.
  • Create somewhere on disk a custom_frameworks folder, copy the framework there and then from the Document Type Association / Locations preferences page add in your Additional frameworks directories list the path to the custom_frameworks folder.
  • Distribute the framework along with a project.

    Follow these steps:
    1. On your local drive, create a directory with full write access, containing the project files and a custom_frameworks folder containing your dita-extension.
    2. Start the application, go to the Project view and create a project. Save it in the newly created directory.
    3. In the Document Type Association / Locations preferences page, select Project Options at the bottom of the page.
    4. Add in the additional framework directories list an entry like ${pd}/custom_frameworks.
    5. Add other resources to your project, for example you can have all your DITA content located inside the project folder.
    6. You can then share the new project directory with other users. For example you can commit it to your version control system and have they update their working copy. When they open the customized project file in the Project view, the new document type becomes available in the list of Document Types.
  • Deploy the framework/document type configuration as an add-on.

After your team members install the framework they can check in Document Type Association preferences page in the list of Document Types to see if the framework is present and if it appears before the bundled DITA framework (meaning that it has higher priority).

Friday, July 17, 2015

Controlled Attribute Values (Part 2 - Advanced)

Share to Facebook Share to Twitter Email This Share on Google Plus Share on Tumblr

As already presented in Controlled Attribute Values for your DITA Project, Oxygen allows you to add or replace possible values for attributes or elements based on a simple configuration file. A more complex scenario is one in which in order to decide which values to provide, you need more context information. Let's take this DITA fragment:

<metadata>
    <othermeta name="name" content="value"/>
</metadata>

What we want is to offer proposals for @content but the possible values for @content depend on the value of @name. We will see how we can solve this dependency.

The configuration file

The configuration file (cc_value_config.xml) allows calling an XSLT stylesheet and that's just what we will do:
<match elementName="othermeta" attributeName="content">
    <xslt href="meta.xsl" useCache="false"/>
</match>

As you can see, we can't express the dependency between @content and @name inside the configuration file . I also want to mention that because the values for @content are dynamic, we want the XSLT script to execute every time the values are requested (we shouldn't cache the results). We enforce this by setting @useCache to false.

The XSLT script

The XSLT script has access to the XML document (through the documentSystemID parameter) but it lacks any context information, we can't really tell for which othermeta element was the script invoked. To counter this limitation, we will use Java extension functions and we will call Oxygen's Java-based API from the XSLT. Here how it looks:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
    xmlns:tei="http://www.oxygenxml.com/ns/doc/xsl"
    xmlns:prov="java:ro.sync.exml.workspace.api.PluginWorkspaceProvider"
    xmlns:work="java:ro.sync.exml.workspace.api.PluginWorkspace"
    xmlns:editorAccess="java:ro.sync.exml.workspace.api.editor.WSEditor"
    xmlns:saxon="http://saxon.sf.net/"
    xmlns:textpage="java:ro.sync.exml.workspace.api.editor.page.text.xml.WSXMLTextEditorPage"
    xmlns:authorPage="java:ro.sync.exml.workspace.api.editor.page.author.WSAuthorEditorPage"
    xmlns:ctrl="java:ro.sync.ecss.extensions.api.AuthorDocumentController"
    exclude-result-prefixes="xs xd"
    version="2.0">
    <xsl:param name="documentSystemID" as="xs:string"></xsl:param>
    
    <xsl:template name="start">
        <xsl:variable name="workspace" select="prov:getPluginWorkspace()"/>
        <xsl:variable name="editorAccess" select="work:getEditorAccess($workspace, xs:anyURI($documentSystemID), 0)"/>
        <xsl:variable name="pageID" as="xs:string" select="editorAccess:getCurrentPageID($editorAccess)"/>
        
        <xsl:variable name="name" as="xs:string">
            <xsl:choose>
                <xsl:when test="$pageID='Text'">
                    <xsl:variable name="textpage" select="editorAccess:getCurrentPage($editorAccess)"/>
                    <!-- In the text page, the context is the @content attribute -->
                    <xsl:value-of select="textpage:evaluateXPath($textpage, 'xs:string(./parent::node()/@name)')"/>
                </xsl:when>
                <xsl:when test="$pageID='Author'">
                    <xsl:variable name="authorPage" select="editorAccess:getCurrentPage($editorAccess)"/>
                    <xsl:variable name="caretOffset" select="authorPage:getCaretOffset($authorPage)"/>
                    <xsl:variable name="ctrl" select="authorPage:getDocumentController($authorPage)"/>
                    <xsl:variable name="contextNode" select="ctrl:getNodeAtOffset($ctrl, $caretOffset)"/>
                    <!-- In the author page, the context is the "othermeta" element -->
                    <xsl:value-of select="ctrl:evaluateXPath($ctrl, 'xs:string(@name)', $contextNode, false(), false(), false(), false())[1]"/>
                </xsl:when>
            </xsl:choose>
        </xsl:variable>
        
        <items>        
            <xsl:choose>
                <xsl:when test="$name = 'temperatureScale'">
                    <item value="Celsius" annotation="(symbol C)"/>
                    <item value="Fahrenheit" annotation="(symbol F)"/>
                </xsl:when>
                <xsl:when test="$name = 'measurement'">
                    <item value="Metric" annotation="Metric system"/>
                    <item value="Imperial" annotation="Also known as British Imperial"/>
                </xsl:when>
            </xsl:choose>
        </items>
    </xsl:template>    
</xsl:stylesheet>

It is also worth mentioning that in the next Oxygen version (17.1) we will provide a more elegant solution to this situation. The XSLT script will receive a new parameter, an XPath expression that will identify the element for which content completion was invoked. But maybe we will talk about that in a future post...

Wednesday, July 15, 2015

Controlled Attribute Values for your DITA Project

Share to Facebook Share to Twitter Email This Share on Google Plus Share on Tumblr

Frequently when editing DITA content you will feel the need to enforce a controlled set of values when editing certain attributes. For example you may want to impose that the values for the @outputclass attribute on the element codeblock are either language-xml or language-css. This is useful in order to remind writers that any other value will not be interpreted by the build process in a significant manner.

Oxygen has a couple of easy ways in which controlled values can be imposed for certain attributes:
  1. You can edit the XML configuration file OXYGEN_INSTALL_DIR/frameworks/dita/resources/cc_value_config.xml and provide additional entries. In the case of our small example for providing controlled values for the @attribute the configuration file should contain an additional entry:
    <match elementName="codeblock" attributeName="outputclass">
     <items action="addIfEmpty">
      <item value="language-xml" annotation="XML Syntax Highlight"/>
      <item value="language-css" annotation="CSS Syntax Highlight"/>
     </items>     
    </match>
    Besides providing a hard-coded list of values the content completion configuration file is flexible enough to allow calling an XSLT stylesheet which could retrieve those values from other sources (for example via HTTP from an Exist database).
  2. Provide those controlled values via a Subject Scheme Map (my favorite). Coming back to our example, you can create a small Subject Scheme map with the file name controlledValues.ditamap and the content:
    <!DOCTYPE subjectScheme PUBLIC "-//OASIS//DTD DITA Subject Scheme Map//EN""map.dtd"> 
    <subjectScheme>
        <subjectHead>
            <subjectHeadMeta>
                <navtitle>Provide controlled attributes</navtitle>
            </subjectHeadMeta>
        </subjectHead>
        <hasInstance>
            <subjectdef keys="languageTypeKey">
                <subjectdef keys="language-xml">
                    <topicmeta>
                        <navtitle>XML Syntax Highlight</navtitle>
                    </topicmeta>
                </subjectdef>
                <subjectdef keys="language-css">
                    <topicmeta>
                        <navtitle>CSS Syntax Highlight</navtitle>
                    </topicmeta>
                </subjectdef>
            </subjectdef>
        </hasInstance>
        <enumerationdef>
            <elementdef name="codeblock"/>
            <attributedef name="outputclass"/>
            <subjectdef keyref="languageTypeKey"/>
        </enumerationdef>
    </subjectScheme>
    then you can refer to it from your main DITA Map like:
    <topicref href="controlledValues.ditamap" format="ditamap" type="subjectScheme"/>
  3. If the attributes on which you want to impose certain values are DITA profiling attributes, you can go to the Oxygen Preferences->Editor / Edit modes / Author / Profiling/Conditional Text page and define the set of allowed values for them.

The only problem with the first approach is the fact that validation will not impose those values and writers will not receive validation error messages if they set another value for the specific attribute. So you will probably need to add a Schematron check in order to signal errors when a certain attribute's value does not match the list of controlled attribute values. For both the second and third approaches, validation will warn the writers if certain attribute values do not match values in the controller values list.

Monday, June 22, 2015

DITA OT PDF Customization - Tables with Alternate Row Background Colors

Share to Facebook Share to Twitter Email This Share on Google Plus Share on Tumblr

Based on this forum thread I will try to give some steps in which you can create your own DITA Open Toolkit PDF customization folder for customizing a table to have alternate row background colors.

  1. First of all you need to know the XSLT template that you need to override.
    • You can open a DITA topic which has a table inside it and select in the Outline view the table row. The Attributes view will show you its @class attribute value which is - topic/row .
    • Use the Find/Replace in Files tool to search in the PDF plugin folder (for example DITA-OT-DIR/plugins/org.dita.pdf2/) for the string topic/row.
    • In the XSLT stylesheet DITA-OT-DIR/plugins/org.dita.pdf2/xsl/fo/tables.xsl you will find a template which matches all rows from a table body:
          <xsl:template match="*[contains(@class, ' topic/tbody ')]/*[contains(@class, ' topic/row ')]">
              <fo:table-row xsl:use-attribute-sets="tbody.row">
                  <xsl:call-template name="commonattributes"/>
                  <xsl:apply-templates/>
              </fo:table-row>
          </xsl:template>
      That is the template which you will need to overwrite in your customization.
  2. Copy the entire folder DITA-OT-DIR/plugins/org.dita.pdf2/Customization to an external location. For example in my case I copied it to my Desktop.
  3. Renamed in that copied folder the catalog.xml.orig file to catalog.xml, edit it and uncomment the line:
      <uri name="cfg:fo/xsl/custom.xsl" uri="fo/xsl/custom.xsl"/>
    This custom catalog file will be automatically used to contribute in the PDF publishing process with high priority the XSLT stylesheet located in Customization/fo/xsl/custom.xsl.
  4. Rename in the Customization/fo/xsl folder the custom.xsl.orig file to custom.xsl. This stylesheet will contain all your template overrides.
  5. Overwrite in the custom.xsl the original template like:
        <xsl:template match="*[contains(@class, ' topic/tbody ')]/*[contains(@class, ' topic/row ')]">
            <fo:table-row xsl:use-attribute-sets="tbody.row">
                <xsl:choose>
                    <xsl:when test="(count(preceding-sibling::*[contains(@class, ' topic/row ')]) mod 2) = 0">
                        <!-- Even row, light blue -->
                        <xsl:attribute name="background-color">rgb(210, 222, 253)</xsl:attribute>
                    </xsl:when>
                    <xsl:otherwise>
                        <!-- Odd row, white -->
                        <xsl:attribute name="background-color">white</xsl:attribute>
                    </xsl:otherwise>
                </xsl:choose>
                <xsl:call-template name="commonattributes"/>
                <xsl:apply-templates/>
            </fo:table-row>
        </xsl:template>
  6. If you want the table frame border colors to have a custom color you can override some attribute sets defined in the DITA-OT-DIR/plugins/org.dita.pdf2/cfg/fo/attrs/tables-attr.xsl:
        <xsl:attribute-set name="table__tableframe__top" use-attribute-sets="common.border__top">
            <xsl:attribute name="border-top-color">blue</xsl:attribute>
        </xsl:attribute-set>
        <xsl:attribute-set name="table__tableframe__bottom" use-attribute-sets="common.border__bottom">
            <xsl:attribute name="border-bottom-color">blue</xsl:attribute>
        </xsl:attribute-set>
        <xsl:attribute-set name="table__tableframe__right" use-attribute-sets="common.border__right">
            <xsl:attribute name="border-right-color">blue</xsl:attribute>
        </xsl:attribute-set>
        <xsl:attribute-set name="table__tableframe__left" use-attribute-sets="common.border__left">
            <xsl:attribute name="border-left-color">blue</xsl:attribute>
        </xsl:attribute-set>ou
  7. Edit your PDF transformation scenario and set the parameter customization.dir to point to your customization folder.
  8. Publish and enjoy :)

If you want to create a DITA Open Toolkit plugin to achieve the same result you can use the dita.xsl.xslfo plugin extension to contribute your own XSLT stylesheet to the publishing process:
http://blog.oxygenxml.com/2013/12/creating-simple-dita-open-toolkit.html

Wednesday, June 03, 2015

How to Host a Webinar

Share to Facebook Share to Twitter Email This Share on Google Plus Share on Tumblr

We periodically host webinars using the GotoWebinar platform. We have two main actors, the host and the presenter and for any other company or consultant who wants to host webinars I'm attaching below a general set of things the host needs to do during the webinar:

  • Half an hour before the start time the host starts the webbinar from the Go To Webinar panel → My Webinars

  • The host (main organizer) and the secondary actors (presenter and members of staff) log in, they are all made organizers.
  • The organizer and presenter test the sound.
  • All presenters need to:
    • Set resolution to 1280 x 800. (Good for recording the webinar).
    • The windows start-up menu needs to be in auto hide mode.
    • The Desktop needs to be cleaned of clutter in order not to distract watchers.
    • All useless applications need to be closed. For example the email application could show email notifications during the presentation.
    • If you are presenting things in the web browser, please make sure you have no extra tabs opened in it.
    • The host opens the power point and goes to full screen.
  • Exactly at the scheduled hour the host presses the Start Broadcast button and presses the Show my screen option. The staff member in charge for recording will start it on his computer.
  • The first presentation slide can have the names of the host and the presenter and the title of the webinar.
  • Host starts speaking: "Hello everybody, my name is X and I will be this webinar's host. I invited my coleague Y to present this webinar covering Z support in Oxygen. This webinar will focus mainly on ... "
  • The second slide is the Agenda.
  • Host continues to speak: "Our agenda today starts with an introduction followed by Y's presentation then we will have a dedicated Q&A section at the end followed by a quick overview of upcoming events, webinars and conferences. "
  • The third slide is presented, the Questions slide.
  • Host speaks: "You do not need to wait until the dedicated Q&A section to ask questions. You can ask questions at any time during the webinar using the Questions panel from the Go to Webinar interface. Some of my coleagues who have already joined the webinar will answer your questions. At the end we'll go over some of the relevant questions. This webinar is recorded and a recording as well as sample files used during the webinar will be made available in a couple of days. "

  • Fourth slide. Host continues to speak: "Before Y will start his presentation I would like you yo answer the following questions..."
  • And the host releases the pre-created polls. He presses Start on a poll, talks about choices, waits a little then closes the poll and shares the results, closes the poll and then shares the results. Then the results are discusses and then the poll is hidden. And so on for each poll.
  • The fifth slide, the host makes Y the presenter, Y will start presenting for about 45 minutes.
  • During the presentation the host looks over questions, he answers some of them.
  • Y has finished the presentation and thanks for the attendance.
  • The host un-mutes himself and starts speaking without sharing his screen: "Thank you Y for this very nice presentation on Z. We covered a lot of ground today. Let's go over some of the questions.... "
  • Host takes the screen and talks over the last two slides, the one about future seminars and the one about future conferences.
  • Host asks Y if he has anything else to add, then they both thank the audience, then mute all. The webinar is left opened a little bit more in order for attendees to be able to ask additional questions.
  • End webinar. File -> Leave Webinar.

  • Eat a slice of pizza and relax, talk about what went wrong, something always does :)