Also see the XMLC 2.2 Release Note, XMLC 2.2.1 Release Note, XMLC 2.2.2 Release Note, XMLC 2.2.3 Release Note, XMLC 2.2.4 Release Note, XMLC 2.2.5 Release Note, XMLC 2.2.6 Release Note, XMLC 2.2.7.1 Release Note, XMLC 2.2.8.1 Release Note, XMLC 2.2.9 Release Note, XMLC 2.2.10 Release Note, XMLC 2.2.11 Release Note, XMLC 2.2.12 Release Note, XMLC 2.2.13 Release Note, XMLC 2.2.14 Release Note, XMLC 2.2.15 Release Note, XMLC 2.2.16 Release Note, XMLC 2.2.17 Release Note, XMLC 2.3 Release Note, and XMLC 2.3.1 Release Note.
Modified LazyDocument.getNodeById(int)
to avoid an ArrayIndexOutOfBoundsException
when nodeId is not a valid array index, i.e., less than zero, by detecting the condition and returning null
. May legitimately occur when an element with an identifier is removed from the document (e.g., when using '-delete-class RemoveMe
') but there is a duplicate identifier (possible when using an HTML parser, though not an XML parser which would report the duplicate as an error at parse time) and the removed element is physically located **after** the element with the duplicate identifier in the source document. Curiously, getElementById()
actually returns the element with the duplicate identifier rather than null as one might reasonably expect after implementing this workaround, which is actually quite a nice surprise and on parity with the standard Xerces DOM.
Note that odd things happen with 3 or more duplicates when one is removed. If the removed duplicate is last, the first duplicate is returned. Place the removed duplicate in any other position and the last duplicate is returned. Odd as it may be, this behavior is identical to the standard Xerces DOM. That said, this odd scenario is only possible when using dynamic loading. When compiling classes for deferred parsing, it is only possible to have more than two duplicates when all but one element utilizes the '-delete-class RemoveMe
' functionality, e.g., <span class="RemoveMe">Mockup Data</span>
. Otherwise, one would experience the error: [xmlc] org.enhydra.xml.xmlc.XMLCException: Duplicate element id "hello", id must be unique after first character is capitalized at org.enhydra.xml.xmlc.compiler.ElementTable.addElement(ElementTable.java:176)
.
Credit goes to Henry Stanaland for discovering and reporting this issue on the user list.
In at least one case where XMLC was being served under Tomcat on a virtual Windows machine, URLs being produced pointing to SSI resources on the classpath ended up with all backslashes instead of the standard forward slashes, e.g., file:\C:\webapps\myapp\WEB-INF\classes\view\includes\MyInclude.ssi
. Interestingly, Java's java.net.URL
class accepts URLs with backslashes, but the org.enhydra.xml.io.InputSourceOps.openSystemId(String)
method used overly strict custom code to evaluate whether a String represented a URL or not, preventing URLs with backslashes from being recognized, and treated, as URLs. Instead, the path was fed directly to a FileInputStream
resulting in a FileNotFoundException
. A fix has been applied that defers URL validation to the URL class. If no MalformedURLException
is thrown, the InputStream
is obtained via the URL, otherwise the path is fed directly to a FileInputStream
.
Credit goes to Yousif Seedham for discovering and reporting this issue on the user list, as well as validating the fix.
Markup based Localization is now supported in XMLC. This feature is disabled by default so as not to incur unnecessary overhead unless desired. Enable by setting the xmlcEnableI18n
context param to true
and use XMLCContext
or set directly using XMLCDeferredParsingFactory.setEnableI18n(true)
.
Once enabled, one may call the new create(XMLCCreateOptions)
method and provide Locale
information using XMLCCreateOptions.setUserLocale(Locale)
and/or XMLCCreateOptions.setFallbackLocale(Locale)
. The user Locale
is meant to be user-defined, i.e., sent by the browser, and is used as the primary Locale
unless null. The fallback Locale
, if provided, is the developer-preferred fallback in case a template corresponding to the user-defined Locale
doesn't exist or the user-defined Locale
is null. The fallback Locale
may also be configured using the xmlcDefaultFallbackLocale
servlet context param, or by setting it directly using XMLCDeferredParsingFactory.setDefaultFallbackLocale(Locale)
, though this is overridden by a non-null XMLCCreateOptions.setFallbackLocale(Locale)
value.
So how does this work? Well, given a base markup file called foo.html
and locales Locale("fr")
(user-defined) and Locale("en", "US")
(developer-preferred fallback), attempts will be made to lookup foo_fr.html, foo_en_US.html, foo_en.html, in that order, and finally fall back to foo.html if no localized version is discovered. Note that if you use deferred parsing rather than dynamic loading - you compile your templates - only compile the base templates, not the localized templates. The appropriate template will be served up given the base template name (stored in the 'XMLC_SOURCE_FILE
' constant of the XMLC compiled class) and the Locales
provided to the create(XMLCCreateOptions)
method. It may help to add <xmlc excludes="**/*_*.*ml" .../>
to avoid compiling locale-named templates.
L10nTask
Ant Task!To ease translation efforts, a new L10nTask
has been created. This Ant task reads base, non-localized, template files, along with associated localized property resource bundle files, and generates localized templates using text substitution. Applying a bit of a twist to standard resource bundle usage, values from base property resource bundle files are used as keys to match text for replacement in base template files. Base property resource bundle file keys, associated with base property resource bundle file values matching base template file text, are used to look up localized values from resource bundles. Finally localized template files are generated, respectively, by creating a copy of the base template file, replacing matched text with localized values, and writing the result to disk with the following file naming convention: [base template file name]_[resource bundle locale string].[base template file extension], e.g., foo.html, foo.properties, and foo_en_US.properties results in foo_en_US.html. Much more functionality is provided, but those are the basics. See the extensively javadoc'ed L10nTask
for details.
Before we get to an example, it's worth mentioning that this task provides much more than basic String matching. Strings provided by base property resource bundle values are used to match text in templates in a sophisticated manner using regular expressions fed to the Perl5.6, Java 1.3+ compatible, JRegex regular expression engine.
Base bundle values are pre-processed, making them literal regex patterns; e.g., "foo (bar)" becomes "foo\s+\(bar\)" which will match the target text regardless of whitespace within it in the template. Also notice that regex meta characters are escaped, ensuring all characters in the string are treated literally (other than the added \s+ between words to match any number of spaces, including line breaks). The only caveat is that line breaks in the target text of original template are lost upon replacement, though non-localized text remains unaffected.
Of course there are some cases where one might want text replaced in one part of the document, but not another. For instance, attributes often contain meaningful values such as Ids and class names for CSS/Javascript or form data. It was for this purpose that the <skipReplace/>
feature was added. This feature allows users significant control over what text gets localized and what doesn't. Regular expressions are used to match contexts where L10n should be avoided. But because regular expressions can be tricky to write, and since skipping attribute L10n is such a common use-case, <skipReplace idref="markup.attrs.all"/>
, <skipReplace idref="markup.attrs.except" idrefSubPrefix="[optional pipe-delimited attribute names with no spaces here, defaults to [X]HTML spec defined '%Text;' attributes]"/>
, and <skipReplace idref="markup.attrs" idrefSubPrefix="[required pipe-delimited attribute names with no spaces here]"/>
have been pre-defined for convenience. For more info, see usage samples below as well as the L10nTask <skipReplace/>
Javadoc.
With that background, now we're ready to dig into an example using the L10nTask
to process the following base template file, base property resource bundle file, and localized resource bundle files...
<html> <head> <title>Hello [Locale] - Base Template</title> </head> <body> <h1>Hello [Locale]</h1> <p>This is the base template file.</p> </body> </html>
hello.locale = Hello [Locale] template.title = Base Template template.desc = This is the base template file
hello.locale = Hello en_US Locale template.title = U.S. English Template template.desc = This is the U.S. English localized template file
hello.locale = Bonjour fr Locale template.title = Français Template template.desc = Ce sont les Français localisée fichier modèle
...results in the following generated localized template files...
<html> <head> <title>Hello en_US Locale - U.S. English Template</title> </head> <body> <h1>Hello en_US Locale</h1> <p>This is the U.S. English localized template file.</p> </body> </html>
<html> <head> <title>Bonjour fr Locale - Français Template</title> </head> <body> <h1>Bonjour fr Locale</h1> <p>Ce sont les Français localisée fichier modèle.</p> </body> </html>
Notice that the example defines an en_US localized property resource bundle file even though the base property resource bundle file was written in U.S. English. This was done to make clear the distinction between the base template/bundle files and localized bundle files; only the base template/bundle files are required to match text. That last point might seem obvious, but what may not be so obvious are the ramifications of choosing not to define a localized property resource bundle file representing the developer-preferred fallback locale.
First, U.S. English speakers would be served a template with odd phrases like "Hello [Locale]". Then again what if we had written the base template in such a way that it matched exactly the phrasing we wanted to present to our U.S. English users (or as our developer-preferred fallback locale)? Would it really have been worth bothering to write an en_US localized property resource bundle file in that case? Let's explore the scenario where the phrasing matches today, but tomorrow we desire a phrasing change.
Recall that phrasing changes of values in the base property resource bundle file require changes to target phrases in the base template file (and vice-versa) in order to maintain matches so that the non-localized phrases can be replaced by localized values. A change in one breaks the other so maintenance doubles; low cohesion, tight coupling.
To avoid this, one can either manually write a custom en_US localized property resource bundle file (as done in the example above) or simply use the L10nTask and set baseBundleLocale="en_US" along with autoGenLocalizedBaseBundle="true" to auto-generate a copy of the base property resource bundle file named as foo_en_US.properties, which then results in a foo_en_US.html generated localized template file. Now phrasing changes for all locales, including the developer-preferred fallback locale, may be made to individual localized property resource bundle files without disturbing the base template/bundle files at all; high cohesion, loose coupling. Given the benefits, and automation provided by the L10nTask
, it is highly recommended to follow this approach for L10n with XMLC.
That said, don't forget to configure XMLC with the developer-preferred fallback locale. In the example below, an XMLC-based webapp is configured to use en_US as the developer-preferred fallback locale.
Optionally define the following in web.xml...
<context-param> <param-name>xmlcEnableI18n</param-name> <param-value>true</param-value> </context-param> <context-param> <param-name>xmlcDefaultFallbackLocale</param-name> <param-value>en_US</param-value> </context-param>
In the servlet, use the following to load XMLC classes/templates...
XMLCContext context = XMLCContext.getContext(this); XMLCDeferredParsingFactory dpFactory = context.getXMLCDeferredParsingFactory(); //Note: The call below is required to enable I18n/L10n if the 'xmlcEnableI18n' //context-param is not defined as above. //dpFactory.setEnableI18n(true); //Note: The fallback Locale used in some examples below is unnecessary if the //'xmlcDefaultFallbackLocale' context-param is defined as above, though it may //still be used to override the default value provided by the context-param. //Note: The setter methods on XMLCCreateOptions return "this", fluent-style, so //options can be conveniently set on one line. Also, one of setXmlcClass(), //setXmlcClassName(), or setDynMarkupFilePath() must be set. All other options //are just that; entirely optional. XMLObject xmlObj = null; xmlObj = dpFactory.create(new XMLCCreateOptions() .setXmlcClass(getXmlcClassFromSomewhere()) .setUserLocale(request.getLocale()) .setFallbackLocale(Locale.US) ); //OR xmlObj = dpFactory.create(new XMLCCreateOptions() .setXmlcClassName(getXmlcClassNameFromSomewhere()) .setUserLocale(request.getLocale()) ); //OR xmlObj = dpFactory.create(new XMLCCreateOptions() .setDynMarkupFilePath(getDynMarkupFilePathFromSomewhere()) .setDynDomFactoryClassName(XercesHTMLDomFactory.class.getName()) .setUserLocale(request.getLocale()) );
L10nTask
Usage (read javadoc for much more detailed information)<taskdef name="l10n" classname="org.enhydra.xml.xmlc.taskdef.L10nTask" classpathref="project.classpath"/> <l10n srcdir="${templates.dir}" includes="*.*ml"/>
Or, utilizing all possible options...
<l10n srcdir="${templates.dir}" includes="*.*ml" destdir="${dest.dir}" bundleDir="${bundle.dir}" bundleDirFlattened="true" masterBundle="${some.dir}/master.properties" masterBundleDominant="true" masterBundleAppliesToAll="false" ssi="true" ssiBase="[path to some directory, no need to set if SSI is already relative to including markup file]" verbose="true" force="false" defaultTemplateEncoding="UTF-8" bundleEncoding="ISO-8859-1" <!-- May use "UTF-8" if building/running under Java6+, negating the need for the native2ascii tool --> baseBundleLocale="en_US" autoGenLocalizedBaseBundle="true"> <skipReplace description="skip replacement of target text inside attributes, except for those defined here" idref="markup.attrs.except" idRefSubPrefix="abbr|alt|label|prompt|standby|summary|title|value"/> <!--skipReplace description="skip replacement of target text inside all attributes, no exceptions" idref="markup.attrs.all"/--> <!--skipReplace description="skip replacement of target text inside those attributes defined here" idref="markup.attrs" idrefSubPrefix="class|id|name"/--> <!--skipReplace description="[some description of what your custom regex prefix/suffix does]" prefix="[some custom regex prefix to the target text]" suffix="[some custom regex suffix to the target text]"/--> </l10n>
To see all this in action, check out the XMLC Tomcat example contained in the distribution.
Last, but not least, some common I18n/L10n utility methods are made available in org.enhydra.xml.xmlc.misc.I18nUtil
.
Removed gnu-regexp dependency in favor of JRegex which supports Perl5.6 regex syntax, including lookahead/lookbehind assertions, and is significantly more performant while remaining Java 1.3+ compliant (since that's XMLC's minimum supported JDK).
Warning! - This may change the behavior of existing -urlregexpmapping
options, as gnu-regexp was intentionally limited to POSIX Extended syntax. While the new Perl5.6 syntax is much more powerful, this change could break some existing expressions. Ensure your expressions are Perl5.6 compatible before you commit to this upgrade!
Updated org.enhydra.xml.io.XmlReader
to use JRegex instead of gnu-regexp (and synchronized XMLC's version with Rome version 1.19). Regular expressions used to look up encoding were also enhanced to be more lenient of line endings.
org.enhydra.xml.xmlc.deferredparsing.ResourceLoader
interface, along with DocumentLoader
, DocumentLoaderImpl
, and XMLCDeferredParsingFactory
improvements (besides I18n/L10n)
The new ResourceLoader
interface looks like...
/** * An interface providing for abstraction of resource loading by * {@link DocumentLoader document loader} implementations. * * @since 2.3.2 */ public interface ResourceLoader { /** * Gets resources, such as XMLC templates and metadata files, from one of an * array of candidate paths relative to a DocumentLoader implementation * chosen context(s) in order of preference. Paths are iterated until one is * found and its URL returned, or none are found and null is returned. * <p> * The candidatePaths may correspond to paths in XMLCDeferredParsingFactory * resource dirs, the classpath, a servlet context, etc... It is entirely * up to implementors how and where to get resources corresponding to these * paths. * </p> * * @param candidatePaths an array of candidate paths from which to load a * resource in order of preference * @return a URL corresponding to one of the candidatePaths or null if not * found * @see DocumentLoader#getResourceLoader() */ public URL getResource(String[] candidatePaths); }
The DocumentLoader
interface now has a new getResourceLoader()
method...
public interface DocumentLoader { public void init(XMLCDeferredParsingFactory factory); /** * Provides a ResourceLoader implementation that abstracts resource paths * from the physical or contextual location of the paths. * * @return a resource loader implementation * @since 2.3.2 */ public ResourceLoader getResourceLoader(); public Document getDocument(Class docClass) throws XMLCRuntimeException; }
While this does force existing custom implementations to implement this method when upgrading to XMLC 2.3.2, it's worth the effort (and most users use, or extend, DocumentLoaderImpl
anyway). It abstracts, standardizes, and centralizes resource loading making it easy to extend and customize. A new ResourceLoaderImpl
implements the resource dir/classpath style of resource loading that DocumentLoaderImpl
has historically performed. But now it's easy to extend and modify this behavior.
New org.enhydra.xml.xmlc.servlet.ServletDocumentLoaderImpl/ServletResourceLoaderImpl
classes have been created to leverage the above and allow loading of resources from the ServletContext
. ServletDocumentLoaderImpl
implements org.enhydra.xml.xmlc.servlet.ServletDocumentLoader
and extends DocumentLoaderImpl
. The XMLCContext
takes care of setting the ServletContext
on ServletDocumentLoader
implementations. ServletResourceLoaderImpl
extends ResourceLoaderImpl
and behavior is identical to the latter, except that it also allows for loading resources from the servlet context, which it performs last after checking resource dirs and the classapth first. This provides for mixed location resource loading and historical behavioral consistency. Of course one can always extend/override DocumentLoader.getResourceLoader()
and implement a ResourceLoader
providing alternate behavior if desired.
Added a number of public final
helper methods to XMLCDeferredParsingFactory
which had been private in DocumentLoaderImpl
. They can now be utilized by DocumentLoader
implementors or otherwise used as needed to load markup and metadata files.
Added the ability to load XMLC metadata files located alongside, and named after, the markup files, only with the .xmlc
extension, e.g., "xmlc/mymarkup.html
" and "xmlc/mymarkup.xmlc
". This means dynamic loading users are no longer limited to using a single, generic, options.xmlc
metadata file and it provides added flexibility for deferred parsing as well. This required removal of the "protected String metaDataFileName(Class docClass)
" method from DocumentLoaderImpl
for technical reasons. The benefit is quite substantial I find it unlikely DocumentLoaderImpl
extenders have overridden this method.
domFactoryClassName
can be configured in the default options.xmlc metadata file. However the optional value passed to XMLCCreateOptions.setDynDomFactoryClassName(String)
or [the newly deprecated] deferredParsingFactory.createFromFile()
methods continues to take precedence.XMLCCreateOptions.setDynMarkupFilePath(String)
or [the newly deprecated] deferredParsingFactory.createFromFile()
, thus normalizing absolute paths to relative, which is what DocumentLoader
implementations generally expect.Updated internal XMLC code to stop using getEncoding()
and, instead, use getInputEncoding()
, falling back to getXmlEncoding()
. The Input Encoding is the encoding the parser used to load the document (made available in DOM Level 3) and should be the most correct.
Related to this change, made use of Encodings.getEncodings().getMIMEPreferred(encoding)
in applicable places, such as BaseDOMFormatter.getEncoding()
.
Made public the utility method Parse.isXmlDocument(MetaData)
for general use. It Determines if the file pointed at by the MetaData <inputDocument url=''/>
attribute is XML. It's either explicitly specified using the MetaData <inputDocument documentFormat=''/>
attribute, set to 'xml
' to assert XML format or 'html
' to assert NOT XML format, or, if not specified, must be determined by looking at the file for an '<?xml
' prolog. As such, setting the <inputDocument documentFormat=''/>
attribute to either 'xml
' (-docformat xml) or 'html
' (-docformat html) will improve performance slightly.
Moved org.enhydra.xml.io.XMLReader
encoding detection from org.enhydra.xml.xmlc.metadata.InputDocument.getInputSource()
to org.enhydra.xml.xmlc.compiler.Parse.parse(MetaData)
(where it should have been all along). Now inputDocument.getInputSource()
simply returns an InputSource
populated with nothing more than the systemId
and encoding
(see Parse.parse(MetaData)
Javadoc for details). This avoids unnecessary XMLReader
encoding detection that used to happen every time inputDocument.getInputSource()
was called. Note this means that the encoding provided by inputDocument.getInputSource()
is that which was configured in the MetaData (or a default if not explicitly configured), not detected encoding. That is now left to the caller.
Finally, improved/corrected the way the encoding used to load documents is chosen. For previous XMLC 2.3.x (as opposed to 2.2.xx) releases, the default fallback encoding for XML documents was ISO-8859-1
where it should have been UTF-8
. With the latest enhancements, encoding is chosen using the following hierarchy...
XMLReader
(BOM or XML prolog). If not detected, then...inputDocument.getInputSource()
in order of...
<html encoding=''/>
attribute or, if not specified, then...UTF-8
" if the document is determined to be XML by Parse.isXmlDocument(MetaData)
, otherwise...ISO-8859-1
is used.Meticulously clarified javadoc describing available context params and their expected values. Some of the documentation was just plain wrong and some was missing.
Added xmlcReparseDocumentLoader
context param, replacing the deprecated, but still recognized, xmlcRecompilationHandler
which allows one to define a custom org.enhydra.xml.xmlc.deferredparsing.DocumentLoader
. The default is org.enhydra.xml.xmlc.deferredparsing.DocumentLoaderImpl
.
Removed xmlcReloading
context param, deprecated set/getXMLCFactory()
methods, and added set/getXMLCDeferredParsingFactory()
methods since org.enhydra.xml.xmlc.deferredparsing.XMLCDeferredParsingFactory
is the only XMLCFactory produced by XMLCContext and supported by XMLC 2.3+. Of course XMLCDeferredParsingFactory
extensions are allowed.
Added xmlcEnableI18n
(true
to enable) and xmlcDefaultFallbackLocale
(e.g., en_US
) context params to support I18n/L10n features.
Documented the existing xmlcContextImpl
context param, used to configure a custom extension of XMLCContext
. A valid value would be the FQCN of the custom XMLCContext
class. This was previously undocumented. It's not overly flexible, as it requires a specific constructor signature to be defined. Nevertheless, it's there for use.
Clarified behavior for formatting DocType. Here's how it goes...
OutputOptions.setPublicId("myPublicId")
or OutputOptions.setSystemId("mySystemId")
is set to a non-null value, then BOTH values will be used to override the document's public/system Id, never a mix of a single non-null override value, plus the document's alternate DocType value, as used to be the case.OutputOptions
a DocType will be added to the document.OutputOptions
are null, then the document's DocType, if it exists, will appear as is (other than XHTML processed by HTMLFormatter
and HTML processed by XMLFormatter
, more info below...).Note: prior to these changes, HTML5 style (<!DOCTYPE html>
) DocTypes were excluded from serialization. They are now supported. To achieve HTML5 style DocTypes using OutputOptions
, simply set at least one of the public/system Ids to an empty (i.e., all white-space) string, with the other being empty or null.
When public/system Ids are NOT overridden using OutputOptions
, XHTML documents processed by HTMLFormatter
(i.e., OutputOptions.setFormat(OutputOptions.FORMAT_HTML)
) automatically have their DocType public/system Ids re-mapped to HTML4.01 equivalents. Likewise, HTML documents processed by XMLFormatter
(i.e., OutputOptions.setFormat(OutputOptions.FORMAT_XHTML)
) automatically have their DocType public/system Ids re-mapped to XHTML1.0 equivalents, with other non-HTML DocTypes, such as the various other XHTML DocTypes, remaining untouched.
Added new OutputOption.setEnableXMLCDATAHack(boolean)
, which is disabled by default. The CDATA hack (using the CDATASection
node to pass though unparsed markup without embedding it within <![CDATA[]]>
) only used to apply to HTML (and HTML formatted as XHTML). It is now an option that must be explicitly enabled when formatting as XML/XHTML. This option is made available for consistency with existing HTML formatting features, but disabled by default because XML/XHTML requires well-formedness and may result in non-well-formed output. You have been warned!
Keep in mind that, when true, this affects serialization of both CDATA sections pre-defined in the markup as well as CDATASection
nodes added to the DOM at runtime as there is simply no way to make a distinction between the two situations at serialization time.
Note that, generally, CDATA sections in XHTML aren't really meaningful [disregarding the XML CDATA hack feature], as browsers treat it as if it were simply a comment, e.g., <!--[CDATA[<p>contents of XHTML CDATA comment</p>]]-->
, as can be seen by doing "View Selection Source" in Firefox. Of course there are times when CDATA sections are actually desirable in XHTML, such as within <script>
and <style>
tags [containing content]. These are an exception to the XML CDATA Hack. No matter the value set for the XML CDATA hack, if said tags contain CDATA sections, CDATA sections will be preserved by the XMLFormatter
. For greatest browser compatibility, it is recommended that users place script/style type comments around the CDATA, e.g., /*<![CDATA[*/...script/style content here.../*]]>*/
, which is compatible with browser HTML parsers, and specifically prevents content from being parsed as markup by browser XML parsers.
XHTML documents processed by the HTMLFormatter
now have xmlns
stripped and xml:lang
re-mapped to lang
(the converse of what the XMLFormatter
does to HTML documents).
Applied minor tweaks to make compatible with Google App Engine. Note that in order to work, all resources in your XMLC application must be served from either the classpath or the servlet context (i.e., using org.enhydra.xml.xmlc.servlet.ServletDocumentLoaderImpl
). Attempts to configure xmlcReparseResourceDirs
, either in web.xml or directly on the XMLCDeferredParsingFactory
, will be ignored with java.security.AccessControlException
exceptions caught and logged at the INFO
level. Finally, ensure that any relative references to XMLC-runtime-parsed server-side-includes resolve to a location within the webapp. That is, make sure that, for example, "../../myinclude.ssi" moves back directories no further from the including file than the context root directory.
org.enhydra.xml.dom.DOMOps
methods
A number of DOM methods were being called by reflection. This was an overlooked legacy from early attempted support at experimental DOM3 methods. Now that XMLC 2.3.x fully supports DOM3, this is unnecessary and XMLObject/XMLObjectImpl
has been updated to call the appropriate DOM3 methods directly (and deprecated the older ones corresponding to those deprecated in DOMOps
). There are, however, 2 special cases of note.
XMLObjectImpl.setEncoding(String)
has no corresponding DOM3 method to call. It's supposed to be read-only, though Xerces2 implements it to update the value returned by Document.getXmlEncoding()
(but warns it's there to support legacy code and shouldn't be called by new code). As such, the reflective call is left in-place to support legacy code (as well as some XMLC internal code).
DOMOps.getContentDocument(HTMLElement)
was completely removed as it never did anything but throw an UnsupportedOperationException
because of the improper way it was implemented. In any case, Xerces does not support it at all. XHTMLFrameElementImpl
, XHTMLIFrameElementImpl
, and XHTMLObjectElementImpl
which all implement this method and used to point at the DOMOps
implementation now simply return null
. The getContentDocument()
method is HTML DOM Level 2 API that leaked into the JDK1.4+ API, somehow, so we have to implement the method to build under JDK1.4+. But there's no need to make it actually do anything since it's not part of the legitimate HTML Level 1 DOM that XMLC/Xerces supports.
The Tomcat example app has been enhanced to illustrate usage of the new L10nTask
, providing a number of localized page examples as well as providing links to quickly view each supported locale.
Made use of a new decorator template in the Preview
servlet, which is based on the CSS Framework by Mike Stenhouse. A new xmlc.demo.DOMDecorator
is used to push in the content pages into the decorator template (more below).
Added links to all the pages via the decorator template for both the request parameter based xmlc.demo.ReloadTest
and the request path info based xmlc.demo.Preview
servlets.
In addition, all page links now work both on and offline. JRegex regular expression support via -urlregexpmapping
is used to rewrite the offline links to their runtime servlet equivalents, thus taking advantage of one of the main selling points of XMLC: usable mockups may serve as fully functional templates with ZERO modification!
Added a minimal /WEB-INF/appengine-web.xml
to allow for running under the Google App Engine desktop simulator. Also modified buld.xml to copy all resource directory hosted markup resources to /WEB-INF/xmlc
for resource loading fallback since no File IO is allowed when running under Google App Engine.
While no template modifications are required, there is some extra runtime modification required. However, these modifications are generic and are implemented using a few org.w3c.dom.traversal.NodeFilter
implementations and a DOM decorator utility class making heavy use of org.w3c.dom.ranges.Range
, all while hiding complexity...
xmlc.demo.AbstractPathModifierNodeFilter
- serves as a base class for URI-path related attribute modifications.xmlc.demo.CompoundNodeFilter
- allows for applying multiple node filters in one pass.xmlc.demo.ParamPropagatorNodeFilter
- extends AbstractPathModifierNodeFilter
and propagates request parameters to links so that navigation from link to link maintains state without resorting to sessions.
xmlc.demo.URIParamParser
- used by ParamPropagatorNodeFilter
to parse the query portion, if it exists, of URI path attributes as well as format the parameters back to a query string again (after merging attribute params with request params).xmlc.demo.PathQualifierNodeFilter
- extends AbstractPathModifierNodeFilter
and qualifies URI path attributes when paths are found to be unqualified. This is necessary, for example, when linking, relatively, to the ReloadTest
servlet when the Preview
servlet is being used to view pages. Without qualifying the path (i.e., "/xmlc/") the extra path info changes the base URL for relatively defined paths, breaking the links.xmlc.demo.DOMDecorator
- A class that makes it easy to decorate a DOM with Strings and Nodes. Nodes are adopted as needed relieving the burden of manually adopting nodes. Advanced DOM techniques, such as DOM Level 2 Document Ranges, are made possible without exposing complexity to the user.xmlc.demo.ValidatingDocumentLoader
- extends ServletDocumentLoaderImpl
and provides a custom ValidatingResourceLoader
that prevents loading user-defined paths referring to locations within "WEB-INF
" or "META-INF
", for security, but also allows for looking up legitimate paths relative to "WEB-INF/xmlc
".While the above code took a bit of time and effort, up-front, to write, it is entirely reusable and transparent. Configure and forget; it just works, allowing developers to concentrate on application logic. Study the classes for details and usage. These classes, or something like them, may end up in the XMLC core in a future release. For now, they will be kept as part of the demo for experimentation.
Updated to Xerces 2.10.0, xml-apis 1.4.01, NekoHTML 1.9.14, JRegex 1.2_01, ASM 3.3, Jaxen 1.1.3, commons-jxpath 1.3, and Log4j 1.2.16
Removed gnu-regexp library dependency