is it possible to disable-output-escaping twice in

2019-09-15 01:53发布

问题:

I have XML that has encoded HTML data. I am trying to render the data but can't seem to figure out how. Best I can tell is I need to disable-output-escaping="yes" twice but not sure how to do that.

For example, this is a snippet of my XML:

<root>
    <node value="&amp;lt;b&amp;gt;body&amp;lt;/b&amp;gt;" />
</root>

My XSLT is outputting HTML. Here is the rendered output (the HTML source) with various options

  • <xsl:value-of select="@value" /> outputs &amp;lt;b&amp;gt;hi&amp;lt;/b&amp;gt;
  • <xsl:value-of select="@value" disable-output-escaping="yes" /> outputs &lt;b&gt;hi&lt;/b&gt;

I would like it to output <b>hi</b> to the HTML source so its actually rendered as a bolded hi. Does that make sense? Is that possible?

回答1:

Escaping is the process of turning < into &lt;. If you disable escaping, it will leave < as <. What you want to achieve is to turn &lt; into <, which would normally be called "unescaping".

In the normal course of events, a parser performs unescaping, while a serializer performs escaping. So if you want to unescape characters, you need to put them through a parsing process, which means you need to take the content of the @value attribute and put it through an operation like fn:parse-xml-fragment() in XPath 3.0, or an equivalent extension function in your chosen processor.



回答2:

Assuming Sharepoint as a Microsoft .NET product uses XslCompiledTransform you could try to implement the unescaping and parsing with extension "script" (C# or VB or JScript.NET code embedded in XSLT) as follows:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:msxsl="urn:schemas-microsoft-com:xslt"
  xmlns:mf="http://example.com/mf"
  exclude-result-prefixes="msxsl mf">


  <msxsl:script language="C#" implements-prefix="mf">
    <msxsl:using namespace="System.IO"/>
    public string Unescape(string input)
    {
    XmlDocument doc = new XmlDocument();
    XmlDocumentFragment frag = doc.CreateDocumentFragment();
    frag.InnerXml = input;
    return frag.InnerText;
    }

    public XPathNavigator ParseXml(string xmlInput)
    {
    using (StringReader sr = new StringReader(xmlInput))
    {
    return new XPathDocument(sr).CreateNavigator();
    }
    }
  </msxsl:script>

  <xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />

  <xsl:template match="/">
    <html>
      <head>
        <title>Test</title>
      </head>
      <xsl:apply-templates/>
    </html>
  </xsl:template>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="node">
    <div>
      <xsl:copy-of select="mf:ParseXml(mf:Unescape(@value))" />
    </div>
  </xsl:template>

</xsl:stylesheet>

If you have access to an XSLT processor (like any version of Saxon 9.7 or Exselt or the latest Altova or XmlPrime) supporting the XPath 3 functions parse-xml and parse-xml-fragment you can write that template without extension functions (in a version="3.0" stylesheet) as

<xsl:template match="node">
    <div>
        <xsl:copy-of select="parse-xml(string(parse-xml-fragment(@value)))"/>
    </div>
</xsl:template>


回答3:

Output your result with disable-output-escaping, then treat it again in another XSL with disable-output-escaping.



标签: html xml xslt