tags:

views:

248

answers:

2

I have an xml document with a node containing the escaped xml serialization of another object, as in this example:

<attribute>
  <value>
    &lt;map&gt;
      &lt;item&gt;
        &lt;src&gt;something&lt;/src&gt;
        &lt;dest&gt;something else&lt;/dest&gt;
      &lt;/item&gt;
    &lt;/map&gt;  
  </value>
</attribute>

How can I apply an xslt template to the inner xml? In particolar, I would like to get an html table with the couples src/dest:

| src       | dest           |
| something | something else |
+1  A: 

Extract the value attribute into an XML document of it's own and transform that.

You will not be able to do this in a single XSLT without alot of substring replacements.

If you can control the format of the XML document, consider putting the node data into a CDATA section and not escaping the < and >.

Oded
"You will not be able to do this in a single XSLT", period. Because a string is a string is a string, no matter if it looks like XML. With some extension function maybe, but otherwise not in one step.
Tomalak
@Tomalak, theoretically, you can analyze a string in XSLT and output a corresponding node tree. So it's not true that "You will not be able to do this in a single XSLT, period." However it would be hairy and maybe not worth it.
LarsH
@Oded, I don't see how putting the data into a CDATA section would help. Maybe you're just saying that would let the author of the XML avoid typing so many entities. It wouldn't change the need to parse that inner XML, right?
LarsH
@LarsH - correct.
Oded
@LarsH: I was referring to vanilla XSLT 1.0, where you indeed cannot do this in a single step. Of course there are ways to get that done in a single XSLT program, but these are not necessarily portable between processors.
Tomalak
@Tomalak, I too was referring to vanilla XSLT 1.0. I didn't mean `<xsl:analyze-string>`. It can be done portably, but it's not very practical or efficient.
LarsH
@LarsH: Wow, if you mean that it would be possible to implement an XML parser in vanilla XSLT 1.0… yes, that's technically possible. But it's also completely absurd. And it would require an extension function (`node-set()`) to work, which makes it non-portable again. ;-)
Tomalak
@Tomalak: absurd, maybe. Depends on how badly you need it and what alternatives are available. I was objecting to your statement that it was not possible, "period." Regarding `node-set()`, that would only be necessary if you need subsequent transformation, which Oded was suggesting but which the OP did not require. You could output his requested HTML table as you parse.
LarsH
+3  A: 

I would do this as a two-step operation.

Step1.xsl:

<xsl:stylesheet 
  version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:template match="/">
    <root>
      <xsl:apply-templates select="attribute/value" />
    </root>
  </xsl:template>

  <xsl:template match="value">
    <object>
      <xsl:value-of select="." disable-output-escaping="yes" />
    </object>
  </xsl:template>
</xsl:stylesheet>

to produce intermediary XML:

<root>
  <object>
    <map>
      <item>
        <src>something</src>
        <dest>something else</dest>
      </item>
    </map>
  </object>
</root>

Step2.xsl

<xsl:stylesheet 
  version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:template match="object">
    <table>
      <tr>
        <xsl:for-each select="map/item/*">
          <th>
            <xsl:value-of select="name()" />
          </th>
        </xsl:for-each>
      </tr>
      <tr>
        <xsl:for-each select="map/item/*">
          <td>
            <xsl:value-of select="." />
          </td>
        </xsl:for-each>
      </tr>
    </table>
  </xsl:template>
</xsl:stylesheet>

to produce an HTML table

<table>
  <tr>
    <th>src</th>
    <th>dest</th>
  </tr>
  <tr>
    <td>something</td>
    <td>something else</td>
  </tr>
</table>
Tomalak
Nice approach on this.
mallows98
Note that this requires an XSLT processor that has control over serialization; not all do, and so not all processors are required to be able to honor disable-output-escaping. However in a situation where your processor honors d-o-e this is a convenient solution.
LarsH
@LarsH: Most stand-alone processors do support d-o-e, but there are some (like the one embedded in Firefox IIRC) that don't. The alternative would be to have the element content (XML string) parsed as an XML document via an extension function.
Tomalak