// Produce Inline SVG element of resulting XHTML page.
// - copy every attributes
// - copy every sub-elements
template "@* | node()", mode="inline_svg" {
// use real xsl:copy instead copy-of alias from yslt.yml2
if "not(@id = $discardable_elements/@id)"
xsl:copy apply "@* | node()", mode="inline_svg";
// replaces inkscape's height and width hints. forces fit
template "svg:svg/@width", mode="inline_svg";
template "svg:svg/@height", mode="inline_svg";
svgtmpl "svg:svg", mode="inline_svg" svg {
attrib "preserveAspectRatio" > none
apply "@* | node()", mode="inline_svg";
// ensure that coordinate in CSV file generated by inkscape are in default reference frame
template "svg:svg[@viewBox!=concat('0 0 ', @width, ' ', @height)]", mode="inline_svg" {
error > ViewBox settings other than X=0, Y=0 and Scale=1 are not supported
// ensure that coordinate in CSV file generated by inkscape match svg default unit
template "sodipodi:namedview[@units!='px' or @inkscape:document-units!='px']", mode="inline_svg" {
error > All units must be set to "px" in Inkscape's document properties
//////////////// Clone Unlinking
// svg:use (inkscape's clones) inside a widgets are
// replaced by real elements they refer in order to :
// - allow finding "needle" element in "meter" widget,
// even if "needle" is in a group refered by a svg use.
// - if "needle" is visible through a svg:use for
// each instance of the widget, then needle would show
// the same position in all instances
// For now, clone unlinkink applies to descendants of all widget except HMI:Page
// TODO: narrow application of clone unlinking to active elements,
// while keeping static decoration cloned
const "to_unlink", "$hmi_elements[not(@id = $hmi_pages)]//svg:use";
svgtmpl "svg:use", mode="inline_svg"
when "@id = $to_unlink/@id"
xsl:copy apply "@* | node()", mode="inline_svg";
// to unlink a clone, an group containing a copy of target element is created
// that way, style and transforms can be preserved
const "_excluded_use_attrs" {
const "excluded_use_attrs","exsl:node-set($_excluded_use_attrs)";
// include non excluded attributes
foreach "@*[not(local-name() = $excluded_use_attrs/name)]"
const "targetid","substring-after(@xlink:href,'#')";
apply "//svg:*[@id = $targetid]", mode="unlink_clone"{
// clone unlinking is really similar to deep-copy
// all nodes are sytematically copied
svgtmpl "@id", mode="unlink_clone" {
attrib "id" > «$seed»_«.»
svgtmpl "@*", mode="unlink_clone" xsl:copy;
// copying widgets would have unwanted effect
// instead widget is refered through a svg:use.
svgtmpl "svg:*", mode="unlink_clone" {
// node recursive copy ends when finding a widget
when "@id = $hmi_elements/@id" {
// place a clone instead of copying
attrib "xlink:href" > «concat('#',@id)»
xsl:copy apply "@* | node()", mode="unlink_clone" {
/*const "mark" > =HMI=\n*/
const "result_svg" apply "/", mode="inline_svg";
const "result_svg_ns", "exsl:node-set($result_svg)";
function "debug_unlink" {
!debug_output_calls.append("debug_unlink")