Custom Marker Processing
Description
Many customers would like to perform custom processing on their source document markers (markers in FrameMaker, fields in Word, @otherprops in DITA). Custom marker processing can be easily accomplished on the ePublisher platform. Users can accomplish this either with an .xsl only override or can allow UI control over marker behavior. This example project will demonstrate a non-UI, .xsl only approach.
This project documents a customer marker implementation implemented by LindaRose.
Contents
GUID Markers
Customer has source FrameMaker documents which include "GUID" markers. Each "GUID" marker contains a GUID (Globally Unique Identifier), which is used to related published content back to the source. These "GUID" markers are inserted and updated using a custom script in FrameMaker. ePublisher need only preserve the contents of these markers in the rendered output.
GUID Markers with XML+XSL
The XML+XSL format publishes content to an XML structure which can then be transformed by a client-side XSL stylesheet for display within a user browser. The .xml files generated by the XML+XSL format resemble:
<?xml version="1.0" encoding="utf-8"?> <?xml-stylesheet type="text/xsl" href="xsl/document.xsl"?> <wp:Document xmlns:wp="urn:WebWorks-XMLXSL-Container-Schema"> ... </wp:Document>
The key parts to notice are:
Content represented in a custom XML namespace, urn:WebWorks-XMLXSL-Container-Schema
Stylesheet processing instruction, <?xml-stylesheet type="text/xsl" href="xsl/document.xsl"?>, specifies to the browser how this XML document should be rendered for HTML display
Step 1: Emit into XML
To render our "GUID" markers into the XML content, we will need to define the rules for how that content should be rendered by ePublisher. We can do this by creating an override for "Transforms\content.xsl".
<project>\Formats\XML+XSL\Transforms\content.xsl
In the past, we would recommend that users copy over "content.xsl" and keep a full copy in the customization area. Now, since ePublisher 2009.1, it is possible to implement what is termed a minimal override via wwtransform:super. The difference is that minimal overrides only contain the changes we care about. This is possible through XSLT support for "better match" templates.
For example, instead of:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns="urn:WebWorks-XMLXSL-Output-Schema" xmlns:wwxmlxsl="urn:WebWorks-XMLXSL-Output-Schema" xmlns:wp="urn:WebWorks-XMLXSL-Container-Schema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:wwmode="urn:WebWorks-Engine-Mode" xmlns:wwlinks="urn:WebWorks-Engine-Links-Schema" xmlns:wwfiles="urn:WebWorks-Engine-Files-Schema" xmlns:wwdoc="urn:WebWorks-Document-Schema" xmlns:wwsplits="urn:WebWorks-Engine-Splits-Schema" xmlns:wwtoc="urn:WebWorks-Engine-TOC-Schema" xmlns:wwbehaviors="urn:WebWorks-Behaviors-Schema" xmlns:wwnotes="urn:WebWorks-Footnote-Schema" xmlns:wwproject="urn:WebWorks-Publish-Project" xmlns:wwpage="urn:WebWorks-Page-Template-Schema" xmlns:wwlocale="urn:WebWorks-Locale-Schema" xmlns:wwprogress="urn:WebWorks-XSLT-Extension-Progress" xmlns:wwlog="urn:WebWorks-XSLT-Extension-Log" xmlns:wwfilesystem="urn:WebWorks-XSLT-Extension-FileSystem" xmlns:wwuri="urn:WebWorks-XSLT-Extension-URI" xmlns:wwstring="urn:WebWorks-XSLT-Extension-StringUtilities" xmlns:wwunits="urn:WebWorks-XSLT-Extension-Units" xmlns:wwfilesext="urn:WebWorks-XSLT-Extension-Files" xmlns:wwprojext="urn:WebWorks-XSLT-Extension-Project" xmlns:wwimaging="urn:WebWorks-XSLT-Extension-Imaging" xmlns:wwexsldoc="urn:WebWorks-XSLT-Extension-Document" exclude-result-prefixes="xsl msxsl wwmode wwlinks wwfiles wwdoc wwsplits wwtoc wwbehaviors wwnotes wwproject wwpage wwlocale wwprogress wwlog wwfilesystem wwuri wwstring wwunits wwfilesext wwprojext wwimaging wwexsldoc" > <xsl:key name="wwsplits-files-by-groupid-type" match="wwsplits:File" use="concat(@groupID, ':', @type)" /> <xsl:key name="wwsplits-frames-by-id" match="wwsplits:Frame" use="@id" /> <xsl:key name="wwtoc-entry-by-id" match="wwtoc:Entry" use="@id" /> <xsl:key name="wwbehaviors-paragraphs-by-id" match="wwbehaviors:Paragraph" use="@id" /> <xsl:key name="wwbehaviors-paragraphs-by-relatedtopic" match="wwbehaviors:Paragraph" use="@relatedtopic" /> <xsl:key name="wwbehaviors-frames-by-id" match="wwbehaviors:Frame" use="@id" /> <xsl:key name="wwbehaviors-tables-by-id" match="wwbehaviors:Table" use="@id" /> <xsl:key name="wwbehaviors-markers-by-id" match="wwbehaviors:Marker" use="@id" /> <xsl:key name="wwdoc-paragraphs-by-id" match="wwdoc:Paragraph" use="@id" /> <xsl:key name="wwnotes-notes-by-id" match="wwnotes:Note" use="@id" /> <xsl:key name="wwfiles-files-by-path" match="wwfiles:File" use="@path" /> <xsl:key name="wwproject-property-by-name" match="wwproject:Property" use="@Name"/> <xsl:template name="Breadcrumbs"> ... <original content> </xsl:template> ... <original content> ... </xsl:stylesheet>
one can now create an equivalent override (since 2009.1) with:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns="urn:WebWorks-XMLXSL-Output-Schema" xmlns:wwxmlxsl="urn:WebWorks-XMLXSL-Output-Schema" xmlns:wp="urn:WebWorks-XMLXSL-Container-Schema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:wwmode="urn:WebWorks-Engine-Mode" xmlns:wwlinks="urn:WebWorks-Engine-Links-Schema" xmlns:wwfiles="urn:WebWorks-Engine-Files-Schema" xmlns:wwdoc="urn:WebWorks-Document-Schema" xmlns:wwsplits="urn:WebWorks-Engine-Splits-Schema" xmlns:wwtoc="urn:WebWorks-Engine-TOC-Schema" xmlns:wwbehaviors="urn:WebWorks-Behaviors-Schema" xmlns:wwnotes="urn:WebWorks-Footnote-Schema" xmlns:wwproject="urn:WebWorks-Publish-Project" xmlns:wwpage="urn:WebWorks-Page-Template-Schema" xmlns:wwlocale="urn:WebWorks-Locale-Schema" xmlns:wwprogress="urn:WebWorks-XSLT-Extension-Progress" xmlns:wwlog="urn:WebWorks-XSLT-Extension-Log" xmlns:wwfilesystem="urn:WebWorks-XSLT-Extension-FileSystem" xmlns:wwuri="urn:WebWorks-XSLT-Extension-URI" xmlns:wwstring="urn:WebWorks-XSLT-Extension-StringUtilities" xmlns:wwunits="urn:WebWorks-XSLT-Extension-Units" xmlns:wwfilesext="urn:WebWorks-XSLT-Extension-Files" xmlns:wwprojext="urn:WebWorks-XSLT-Extension-Project" xmlns:wwimaging="urn:WebWorks-XSLT-Extension-Imaging" xmlns:wwexsldoc="urn:WebWorks-XSLT-Extension-Document" exclude-result-prefixes="xsl msxsl wwmode wwlinks wwfiles wwdoc wwsplits wwtoc wwbehaviors wwnotes wwproject wwpage wwlocale wwprogress wwlog wwfilesystem wwuri wwstring wwunits wwfilesext wwprojext wwimaging wwexsldoc" > <xsl:include href="wwtransform:super" /> </xsl:stylesheet>
This type of minimal override helps to isolate custom .xsl code further from the ePublisher defaults without the need for resolving changes for future upgrade with file comparison tools.
NOTE: You can learn more about wwtransform:super over in the WebWorks Wiki.
With this minimal override file in place, we can now add in the necessary custom processing code for operating on our markers. Here, we assume the marker name is "GUID".
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns="urn:WebWorks-XMLXSL-Output-Schema" xmlns:wwxmlxsl="urn:WebWorks-XMLXSL-Output-Schema" xmlns:wp="urn:WebWorks-XMLXSL-Container-Schema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:wwmode="urn:WebWorks-Engine-Mode" xmlns:wwlinks="urn:WebWorks-Engine-Links-Schema" xmlns:wwfiles="urn:WebWorks-Engine-Files-Schema" xmlns:wwdoc="urn:WebWorks-Document-Schema" xmlns:wwsplits="urn:WebWorks-Engine-Splits-Schema" xmlns:wwtoc="urn:WebWorks-Engine-TOC-Schema" xmlns:wwbehaviors="urn:WebWorks-Behaviors-Schema" xmlns:wwnotes="urn:WebWorks-Footnote-Schema" xmlns:wwproject="urn:WebWorks-Publish-Project" xmlns:wwpage="urn:WebWorks-Page-Template-Schema" xmlns:wwlocale="urn:WebWorks-Locale-Schema" xmlns:wwprogress="urn:WebWorks-XSLT-Extension-Progress" xmlns:wwlog="urn:WebWorks-XSLT-Extension-Log" xmlns:wwfilesystem="urn:WebWorks-XSLT-Extension-FileSystem" xmlns:wwuri="urn:WebWorks-XSLT-Extension-URI" xmlns:wwstring="urn:WebWorks-XSLT-Extension-StringUtilities" xmlns:wwunits="urn:WebWorks-XSLT-Extension-Units" xmlns:wwfilesext="urn:WebWorks-XSLT-Extension-Files" xmlns:wwprojext="urn:WebWorks-XSLT-Extension-Project" xmlns:wwimaging="urn:WebWorks-XSLT-Extension-Imaging" xmlns:wwexsldoc="urn:WebWorks-XSLT-Extension-Document" exclude-result-prefixes="xsl msxsl wwmode wwlinks wwfiles wwdoc wwsplits wwtoc wwbehaviors wwnotes wwproject wwpage wwlocale wwprogress wwlog wwfilesystem wwuri wwstring wwunits wwfilesext wwprojext wwimaging wwexsldoc" > <xsl:include href="wwtransform:super" /> <xsl:template match="wwdoc:Marker[@name = 'GUID']" mode="wwmode:textrun"> <xsl:variable name="VarMarker" select="." /> <!-- Emit with GUID wrapper --> <!-- --> <wp:guid> <xsl:for-each select="$VarMarker/wwdoc:TextRun/wwdoc:Text"> <xsl:value-of select="@value" /> </xsl:for-each> </wp:guid> </xsl:template> </xsl:stylesheet>
NOTE: We make sure to assign a namespace prefix to our <guid> element so that we can refer to it during later processing. Users are free to define alternate namespaces and namespace prefixes as required.
WARNING: You may need to switch targets and/or close and reopen your project for ePublisher to locate your new override.
Step 2: Suppress GUID in Rendered HTML
With the customization from Step 1 in place, we can now generated XML content which includes the "GUID" markers as <guid> elements:
<?xml version="1.0" encoding="utf-8"?> <?xml-stylesheet type="text/xsl" href="xsl/document.xsl"?> <wp:Document xmlns:wp="urn:WebWorks-XMLXSL-Container-Schema"> ... <wp:Content> <Title wp:id="998290" wp:type="para" wp:class="Title" xmlns="urn:WebWorks-XMLXSL-Output-Schema">GUID Markers</Title> <Body wp:id="998292" wp:type="para" wp:class="Body" xmlns="urn:WebWorks-XMLXSL-Output-Schema">This paragraph contains a single GUID marker<guid>16561377c914411bafaa3cebd5161e08</guid>.</Body> </wp:Content> </wp:Document>
This is correct so far. However, when this content is rendered by client-side browsers according to the "xsl/document.xsl" stylesheet, the result looks like:
GUID Markers This paragraph contains a single GUID marker16561377c914411bafaa3cebd5161e08.
Review of the rendered HTML shows why we see this result:
<div class="Title" id="998290">GUID Markers</div> <div class="Body" id="998292">This paragraph contains a single GUID marker16561377c914411bafaa3cebd5161e08.</div>
How can we suppress rendering of the <guid> element?
As I mentioned previously, a browser renders XML documents according to the templates defined by the stylesheet processing instruction:
<?xml-stylesheet type="text/xsl" href="xsl/document.xsl"?>
So, to change how <guid> elements are rendered, we need to define a custom "xsl/document.xsl" file.
The default "xsl/document.xsl" is located within the format at "XML+XSL\Files\xsl\document.xsl". We can create an override for this in our project with:
<project>\Formats\XML+XSL\Files\xsl\document.xsl
NOTE: This transform will be handled by a client-side browser, so we cannot create a minimal .xsl override. We must copy the entire file.
Now that our "xsl/document.xsl" override file is in place, we can add the necessary code to suppress rendering of <guid> elements. We will add an XSL match template for those elements at the end of the stylesheet:
<xsl:template match="wp:guid"> <!-- Do nothing! --> <!-- --> </xsl:template> </xsl:stylesheet>
Viewing generated .xml files confirms that <guid> element rendering is now suppressed:
GUID Markers This paragraph contains a single GUID marker.
HTML source:
<div class="Title" id="998290">GUID Markers</div> <div class="Body" id="998292">This paragraph contains a single GUID marker.</div>
WARNING: You may need to switch targets and/or close and reopen your project for ePublisher to locate your new override.
GUID Markers with WebWorks Help
Processing "GUID" markers in WebWorks Help is similar to the approach taken with XML+XSL. We'll start by copying over "Transforms\content.xsl" to the override area:
<project>\Formats\WebWorks Help 5.0\Transforms\content.xsl
Next, we'll remove the existing stylesheet contents and reference them via wwtransform:super:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:wwmode="urn:WebWorks-Engine-Mode" xmlns:wwlinks="urn:WebWorks-Engine-Links-Schema" xmlns:wwalinks="urn:WebWorks-ALinks-Schema" xmlns:wwfiles="urn:WebWorks-Engine-Files-Schema" xmlns:wwdoc="urn:WebWorks-Document-Schema" xmlns:wwsplits="urn:WebWorks-Engine-Splits-Schema" xmlns:wwtoc="urn:WebWorks-Engine-TOC-Schema" xmlns:wwbehaviors="urn:WebWorks-Behaviors-Schema" xmlns:wwnotes="urn:WebWorks-Footnote-Schema" xmlns:wwproject="urn:WebWorks-Publish-Project" xmlns:wwpage="urn:WebWorks-Page-Template-Schema" xmlns:wwlocale="urn:WebWorks-Locale-Schema" xmlns:wwprogress="urn:WebWorks-XSLT-Extension-Progress" xmlns:wwlog="urn:WebWorks-XSLT-Extension-Log" xmlns:wwfilesystem="urn:WebWorks-XSLT-Extension-FileSystem" xmlns:wwuri="urn:WebWorks-XSLT-Extension-URI" xmlns:wwstring="urn:WebWorks-XSLT-Extension-StringUtilities" xmlns:wwunits="urn:WebWorks-XSLT-Extension-Units" xmlns:wwfilesext="urn:WebWorks-XSLT-Extension-Files" xmlns:wwprojext="urn:WebWorks-XSLT-Extension-Project" xmlns:wwimaging="urn:WebWorks-XSLT-Extension-Imaging" xmlns:wwexsldoc="urn:WebWorks-XSLT-Extension-Document" exclude-result-prefixes="xsl msxsl wwmode wwlinks wwalinks wwfiles wwdoc wwsplits wwtoc wwbehaviors wwnotes wwproject wwpage wwlocale wwprogress wwlog wwfilesystem wwuri wwstring wwunits wwfilesext wwprojext wwimaging wwexsldoc" > <xsl:include href="wwtransform:super" /> </xsl:stylesheet>
Now, we can add our custom processing for "GUID" markers. The match template resembles the version used for the XML+XSL format. The difference here is that we want the GUID element to show up in the HTML content yet prevent it from being rendered by the browser.
One approach is to emit a <guid> element in the HTML namespace and use a CSS @style attribute to suppress GUID rendering:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:wwmode="urn:WebWorks-Engine-Mode" xmlns:wwlinks="urn:WebWorks-Engine-Links-Schema" xmlns:wwalinks="urn:WebWorks-ALinks-Schema" xmlns:wwfiles="urn:WebWorks-Engine-Files-Schema" xmlns:wwdoc="urn:WebWorks-Document-Schema" xmlns:wwsplits="urn:WebWorks-Engine-Splits-Schema" xmlns:wwtoc="urn:WebWorks-Engine-TOC-Schema" xmlns:wwbehaviors="urn:WebWorks-Behaviors-Schema" xmlns:wwnotes="urn:WebWorks-Footnote-Schema" xmlns:wwproject="urn:WebWorks-Publish-Project" xmlns:wwpage="urn:WebWorks-Page-Template-Schema" xmlns:wwlocale="urn:WebWorks-Locale-Schema" xmlns:wwprogress="urn:WebWorks-XSLT-Extension-Progress" xmlns:wwlog="urn:WebWorks-XSLT-Extension-Log" xmlns:wwfilesystem="urn:WebWorks-XSLT-Extension-FileSystem" xmlns:wwuri="urn:WebWorks-XSLT-Extension-URI" xmlns:wwstring="urn:WebWorks-XSLT-Extension-StringUtilities" xmlns:wwunits="urn:WebWorks-XSLT-Extension-Units" xmlns:wwfilesext="urn:WebWorks-XSLT-Extension-Files" xmlns:wwprojext="urn:WebWorks-XSLT-Extension-Project" xmlns:wwimaging="urn:WebWorks-XSLT-Extension-Imaging" xmlns:wwexsldoc="urn:WebWorks-XSLT-Extension-Document" exclude-result-prefixes="xsl msxsl wwmode wwlinks wwalinks wwfiles wwdoc wwsplits wwtoc wwbehaviors wwnotes wwproject wwpage wwlocale wwprogress wwlog wwfilesystem wwuri wwstring wwunits wwfilesext wwprojext wwimaging wwexsldoc" > <xsl:include href="wwtransform:super" /> <xsl:template match="wwdoc:Marker[@name = 'GUID']" mode="wwmode:textrun"> <xsl:variable name="VarMarker" select="." /> <!-- Emit with GUID wrapper --> <!-- --> <html:guid style="display: none; visibility: hidden;"> <xsl:for-each select="$VarMarker/wwdoc:TextRun/wwdoc:Text"> <xsl:value-of select="@value" /> </xsl:for-each> </html:guid> </xsl:template> </xsl:stylesheet>
This approach works for FireFox 3.* browsers, yet fails with Internet Explorer 8.
A better approach is to nest the <guid> element within a <span> tag. This gets around rendering differences for unrecognized elements, such as <guid> by different browsers.
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:wwmode="urn:WebWorks-Engine-Mode" xmlns:wwlinks="urn:WebWorks-Engine-Links-Schema" xmlns:wwalinks="urn:WebWorks-ALinks-Schema" xmlns:wwfiles="urn:WebWorks-Engine-Files-Schema" xmlns:wwdoc="urn:WebWorks-Document-Schema" xmlns:wwsplits="urn:WebWorks-Engine-Splits-Schema" xmlns:wwtoc="urn:WebWorks-Engine-TOC-Schema" xmlns:wwbehaviors="urn:WebWorks-Behaviors-Schema" xmlns:wwnotes="urn:WebWorks-Footnote-Schema" xmlns:wwproject="urn:WebWorks-Publish-Project" xmlns:wwpage="urn:WebWorks-Page-Template-Schema" xmlns:wwlocale="urn:WebWorks-Locale-Schema" xmlns:wwprogress="urn:WebWorks-XSLT-Extension-Progress" xmlns:wwlog="urn:WebWorks-XSLT-Extension-Log" xmlns:wwfilesystem="urn:WebWorks-XSLT-Extension-FileSystem" xmlns:wwuri="urn:WebWorks-XSLT-Extension-URI" xmlns:wwstring="urn:WebWorks-XSLT-Extension-StringUtilities" xmlns:wwunits="urn:WebWorks-XSLT-Extension-Units" xmlns:wwfilesext="urn:WebWorks-XSLT-Extension-Files" xmlns:wwprojext="urn:WebWorks-XSLT-Extension-Project" xmlns:wwimaging="urn:WebWorks-XSLT-Extension-Imaging" xmlns:wwexsldoc="urn:WebWorks-XSLT-Extension-Document" exclude-result-prefixes="xsl msxsl wwmode wwlinks wwalinks wwfiles wwdoc wwsplits wwtoc wwbehaviors wwnotes wwproject wwpage wwlocale wwprogress wwlog wwfilesystem wwuri wwstring wwunits wwfilesext wwprojext wwimaging wwexsldoc" > <xsl:include href="wwtransform:super" /> <xsl:template match="wwdoc:Marker[@name = 'GUID']" mode="wwmode:textrun"> <xsl:variable name="VarMarker" select="." /> <!-- Emit with GUID wrapper --> <!-- --> <html:span style="display: none; visibility: hidden;"> <html:guid> <xsl:for-each select="$VarMarker/wwdoc:TextRun/wwdoc:Text"> <xsl:value-of select="@value" /> </xsl:for-each> </html:guid> </html:span> </xsl:template> </xsl:stylesheet>
WARNING: You may need to switch targets and/or close and reopen your project for ePublisher to locate your new override.
Sample Project
A sample project which implements these customizations is available.
This project was developed using ePublisher 2009.2, though it should be compatible with ePublisher 2009.2 and 2009.3 as well. It cannot be used with older versions of ePublisher (2009.1 and earlier) due to project incompatibilities.