2

My XSLT stylesheet generates Bootstrap HTML where some elements may contain data-... attributes to pass additional data to the framework. For example, I have this code to generate a popover element:

<xsl:template match="foo">
  <a href="#" data-toggle="popover" data-placement="top" data-trigger="hover" data-html="true">
    <xsl:attribute name="title">Popover Title</xsl:attribute>
    <xsl:attribute name="data-content">This is some additional content.</xsl:attribute>
    <xsl:text>Link</xsl:text>
  </a>
</xsl:template>

The data-content attribute is supposed to contain additional markup. The resulting output should be something like

<a href="#" ... data-content="This is <em>some</em> additional <a href='#'>content</a>.">Link</a>

How do I generate markup text for the <xsl:attribute> in this case?

(Somewhat related: here and here and here.)

The answers

Thanks for the answers! While I think that kjhughes's answer provides the technically correct solution to implement properly what I need, I think that Ian's answer addresses my question more directly.

Community
  • 1
  • 1
Jens
  • 8,423
  • 9
  • 58
  • 78

3 Answers3

2

You can't put unescaped markup in an attribute value, but you don't need to - if you escape the angle brackets (and any ampersands and quotes-within-quotes) as entity references bootstrap will still render the html properly in the popover.

<a href="#" data-content="This is &lt;em&gt;some&lt;/em&gt; additional &lt;a href='#'&gt;content&lt;/a&gt;.">Link</a>

The simplest way to get this right in the XSLT would be to use a CDATA section:

<xsl:attribute name="data-content"
  ><![CDATA[This is <em>some</em> additional content
    &amp; a <a href="#">link</a>.]]></xsl:attribute>

And the serializer will escape it for you as necessary.

Ian Roberts
  • 120,891
  • 16
  • 170
  • 183
  • Interestingly, the fiddle worked partially: the `` doesn't show but the `` does. – Jens Feb 09 '15 at 07:20
  • @Jens so it does, I tried changing em to strong and that does come out bold so it only appears to be certain tags. Or maybe it's something in bootstrap's css. – Ian Roberts Feb 09 '15 at 08:52
  • @Jens ok, it's jsfiddle's fault - [here's a version with "normalize css" unticked](http://jsfiddle.net/gr5qweku/4/) which renders the `em` as expected. – Ian Roberts Feb 09 '15 at 09:35
  • And to make this just a little more funky, I can use several `CDATA` sections to wrap other XSLT elements. For example: `<![CDATA[<![CDATA[">Link]]>` – Jens Feb 09 '15 at 19:50
0

You cannot generate markup inside of an xsl:attribute because XML does not allow unescaped markup inside of attributes.

Specifically, the grammar rule for AttValue prohibits < altogether and & unless the & is part of a properly formed Reference:

AttValue       ::=      '"' ([^<&"] | Reference)* '"'
                      | "'" ([^<&'] | Reference)* "'"

Supporting definitions:

Reference      ::=      EntityRef | CharRef
EntityRef      ::=      '&' Name ';'
CharRef        ::=      '&#' [0-9]+ ';'
                      | '&#x' [0-9a-fA-F]+ ';'

HTML too, even HTML5, does not allow unescaped markup in attribute values.

Adding escaped markup in attribute values is viable but ugly. Especially for heavily marked-up content, I'd recommend creating the content separately and then associating it procedurally via JavaScript rather than declaratively via attribute values. There are many examples of doing this, including this one mentioned in one of your references.

Community
  • 1
  • 1
kjhughes
  • 106,133
  • 27
  • 181
  • 240
  • I believe the HTML spec is more pertinent here, as that's what OP is generating: "*The attribute value may only contain letters (a-z and A-Z), digits (0-9), hyphens (ASCII decimal 45), periods (ASCII decimal 46), underscores (ASCII decimal 95), and colons (ASCII decimal 58).*" http://www.w3.org/TR/html401/intro/sgmltut.html#h-3.2.2 – michael.hor257k Feb 08 '15 at 21:50
  • @michael.hor257k: Hm. Are you saying that Bootstrap's use of the `data-content` attribute is invalid HTML? – Jens Feb 09 '15 at 07:24
  • @Jens Can you point to an example where they use markup inside the `data-content` attribute? I haven't seen one on the page you linked to. – michael.hor257k Feb 09 '15 at 07:29
  • @michael.hor257k: I just added references to three other questions, all of which have examples of HTML embedded into that attribute (in particular [this](http://stackoverflow.com/questions/13202762/html-inside-twitter-bootstrap-popover) one). – Jens Feb 09 '15 at 07:33
  • @Jens I am not an expert on HTML, but IMHO that is **not** valid HTML. Even if it *may* work (in *some* browsers). Note that at least one of the answers you linked to says the same thing expressly: http://stackoverflow.com/a/8908888/3016153 – michael.hor257k Feb 09 '15 at 07:43
  • @michael.hor257k: Thank you. Considering that, the better (more compatible?) way to attach HTML to the popover's body seems to be Javascript instead of using the `data-content` attribute. – Jens Feb 09 '15 at 07:50
  • @Jens I don't think the actual method by which you populate the attribute's value is of the essence; what matters here is the result, i.e. what ends up as the contents when the page is rendered. – michael.hor257k Feb 09 '15 at 08:07
  • 1
    @Jens, yes, I prefer [**this approach**](http://stackoverflow.com/a/26408903/290085) from your first example, especially when you need a lot of markup. Besides markup not belonging in attribute values for XML or HTML, separate `divs` are easier to create, read, and edit. – kjhughes Feb 09 '15 at 15:33
0

Not an "official" way of doing this, but when using lxml to process the XML and XSLT stylesheets, consider using XSLT extension elements in your stylesheet. Those custom elements allow you to run Python code when elements match during processing, and that code can modify/edit parts of the output document.

Jens
  • 8,423
  • 9
  • 58
  • 78