XML vs HTML

General information

Even though Xeditor is used for editing your XML documents, within Xeditor an (X)HTML representation of your XML document is used. Xeditor uses XSL transformations for this. When loading, the file contenttoeditor.xsl will transform your XML content into HTML. When saving, the transformation editortocontent.xsl will transform the HTML content back to XML.

The HTML representation of the opened XML is quite similar to the original input.

The following XML input

<paragraph>Some text</paragraph>

becomes the following HTML:

<div data-type="paragraph">
<span data-type="text">Some text</span>
</div>

So, basically the key difference is

  • every XML element becomes an HTML element with a data-type attribute with it's value being the name of the XML element
  • text content will be wrapped into an HTML element with the data-type attribute set to text

Upon save, each HTML element will be transformed back to its corresponding XML element.

We already provide you with templates required for the most common tasks. Usually it's not required to add any additional templates, which is still possible though.

Note: All transformation files mentioned in this section are placed in /WEB-INF/xsl/ of your Xeditor project folder.

XML to HTML (contenttoeditor.xsl)

In order to properly transform your XML elements into HTML elements for Xeditor, we prepared a couple for XSL templates that can be reused for the most common use cases. The most important and common steps are:

  • defining elements that are non mixed, and can therefore only contain other elements, but no text
  • defining elements that are mixed and can therefore contain both, text and elements
  • defining list and list item elements
  • defining table elements

It's important to differentiate between elements that don't allow any text (non-mixed) and elements that allow text (mixed), since for the latter, there will be a text node added even if it doesn't contain one.

Lists, list items, and table elements have to be placed in their corresponding template since it has effect on the HTML tag that will be used (e.g. <table> for the table element), which is required for a proper rendering and handling done by the browser.

There's a couple of additional features that can be achieved using the XSL templates:

  • setting elements to read only (user is not able to edit them)
  • setting elements to be not deletable
  • a combination of both
  • setting any additional attributes and / or data flags on the resulting HTML elements, which e.g. might result in some special styling

The following attributes and data-attributes are supported by Xeditor out of the box, but you can also add your own custom ones and add the functionality / styling accordingly.

namevalueseffect
data-editabletrue / falsefalse if element should not be editable
data-removabletrue / falsefalse if element should not be removable
classstringCSS class that should be set on element

Examples

Basic elements

The following lists a couple of sample transformation templates. Please note that all templates used here are already part of your preconfigured transformation file contenttoeditor.xsl.

As the comment indicates, this template is used for elements that can contain other elements, but can't contain any text content. Hence, the template adapts all it's children, but will not create a text node.

<!-- non-mixed -->
<xsl:template match="content | chapter | box | footnote">
<div data-type="{local-name()}">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="* | comment() | processing-instruction()"/>
</div>
</xsl:template>

This template is used for mixed elements, meaning elements that can contain other elements and / or text elements. The key difference to the non-mixed template is that this one will always add a text node to the elements, and therefore enable the user to write in them.

<!-- mixed -->
<xsl:template match="heading | subheading | p | bold | italic | underline | subscript | superscript">
<div data-type="{local-name()}">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()"/>
<xsl:if test="not(* | text())">
<span data-type="text"></span>
</xsl:if>
</div>
</xsl:template>

List and list items

The template for list elements is quite similar to the one used for non-mixed elements. The important difference is that for lists, the proper HTML tag is being used.

<!-- list -->
<xsl:template match="list_ordered | list_unordered">
<ul data-type="{local-name()}">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="* | comment() | processing-instruction()"/>
</ul>
</xsl:template>

For list items you have to templates available, one for list items that contain text directly (mixed) and one for items that use a text container instead (non-mixed):

<!-- list item (non-mixed) -->
<xsl:template match="list_item">
<li data-type="{local-name()}">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="* | comment() | processing-instruction()"/>
</li>
</xsl:template>
<!-- list item (mixed) -->
<xsl:template match="list_item">
<li data-type="{local-name()}">
<xsl:apply-templates select="@*"/>
<xsl:if test="not(text())">
<span data-type="text"></span>
</xsl:if>
<xsl:apply-templates select="node()"/>
</li>
</xsl:template>

Limiting editing options on certain elements

As already mentioned, it's possible to limit the actions a user can perform with certain elements. Elements can be set to being non editable, meaning the user can't add / delete any text of given element. In addition, no child elements can be inserted. Additionally, an element can be set to be unremovable, meaning the element can still be edited, but the user won't be able to delete it. Both flags can also be combined.

Example template for a mixed element that is set to being not editable:

<xsl:template match="non-editable-element">
<div data-type="{local-name()}" data-editable="false">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()"/>
<xsl:if test="not(* | text())">
<span data-type="text"></span>
</xsl:if>
</div>
</xsl:template>

Example template for a mixed element that is set to being not removable:

<xsl:template match="non-removable-element">
<div data-type="{local-name()}" data-removable="false">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()"/>
<xsl:if test="not(* | text())">
<span data-type="text"></span>
</xsl:if>
</div>
</xsl:template>

Example template for a mixed element that is set to being not editable and not removable:

<xsl:template match="non-editable-non-removable-element">
<div data-type="{local-name()}" data-editable="false" data-removable="false">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()"/>
<xsl:if test="not(* | text())">
<span data-type="text"></span>
</xsl:if>
</div>
</xsl:template>

HTML to XML (editortocontent.xsl)

Upon save, Xeditors HTML representation of your XML will be transformed back to proper XML. The transformation templates used for this step can be found in WEB-INF/xsl/editortocontent.xsl of your Xeditor project. Since Xeditors HTML is a basic element containing an data-type attribute indicating the elements name, the most important template of the transformation back to XML is this one:

<!-- default tag -->
<xsl:template match="*[@data-type]" priority="-9">
<xsl:element name="{@data-type}">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="*[@data-type] | comment() | processing-instruction()"/>
</xsl:element>
</xsl:template>

It basically just creates a new XML element, sets its name to the value of the data-type attribute, and calls proper templates for its children. Usually there are no further adjustments on this file required. Since the transformation back to the original XML (mostly) doesn't require any tag specific handling (e.g. usage of <table> tag) it's kept relatively simple.

There's one exception that needs a special template to be added. If your schema uses the CALS table model there's one additonal template that needs to be added. Since the colspec element isn't properly handled by the browser, we add it dynamically on save using the following template:

<!-- table cals -->
<!-- startcol and endcol attributes on entry elements have to be set via javascript in xeditor -->
<xsl:template match="*[@data-type = 'tgroup']">
<xsl:element name="{@data-type}">
<xsl:attribute name="cols"><xsl:value-of select="count(.//*[@data-type = 'colspec'])"/></xsl:attribute>
<xsl:apply-templates select="@*"/>
<xsl:for-each select=".//*[@data-type = 'colspec']">
<colspec colnum="{position()}" colname="col{position()}">
<xsl:apply-templates select="@*"/>
</colspec>
</xsl:for-each>
<xsl:apply-templates select="*[@data-type][@data-type != 'colgroup'] | comment() | processing-instruction()"/>
</xsl:element>
</xsl:template>
<xsl:template match="*[@data-type = 'entry']">
<xsl:element name="{@data-type}">
<xsl:choose>
<xsl:when test="@startcol = @endcol">
<xsl:attribute name="colname">col<xsl:value-of select="@startcol"/></xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="namest">col<xsl:value-of select="@startcol"/></xsl:attribute>
<xsl:attribute name="nameend">col<xsl:value-of select="@endcol"/></xsl:attribute>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="@data-attrvalue-rowspan">
<xsl:attribute name="morerows"><xsl:value-of select="@data-attrvalue-rowspan - 1"/></xsl:attribute>
</xsl:if>
<xsl:apply-templates select="@*[local-name() != 'data-attrvalue-colspan' and local-name() != 'data-attrvalue-rowspan']"/>
<xsl:apply-templates select="*[@data-type] | comment() | processing-instruction()"/>
</xsl:element>
</xsl:template>