Struts2 使用 xslt 结果类型如何把字符串直接作为 Document 内容(终结)

前面两篇:Struts2 使用 XSLTResult 输出页面内容详解 和 Struts2 使用 xslt 结果类型如何把字符串直接作为 Document 内容 对 Struts2 如何使用 xslt 结果和怎么把字符串直接作为 Document 内容进行的讲解、研究和探讨。关于 Action 中的字符怎么直接作为 xslt 的内容已有一种方法,就是把 String 转换成 org.w3c.dom.Document 类型再送给 xslt 文件。


同时也发现 Struts2 使用了 org.apache.struts2.views.xslt.StringAdapter 了对字符串的处理,并提供了 parseStringAsXML 的开关选项(虽然是无从设置它的值),但即使把 parseStringAsXML 设置成了 true,送给 xslt 文件的内容也是被包裹上了 <result> 根节点,xslt 中不得不用 <xsl:template match="/result/你的根节点"> 来应用模板。

通过在上一篇 Struts2 使用 xslt 结果类型如何把字符串直接作为 Document 内容 里琢磨来琢磨去的探寻,着实又走了不少弯路,甚至是误入了歧途,但终究是找到了一个较好的办法来让 Action 直接送 String 表示的 Document 给 xslt 文件。那就是自定义 StringXSLTResult, 继承自 org.apache.struts2.views.xslt.XSLTResult,只需要覆盖它的 getDOMSourceForStack(Object value) 方法。完整的 StringXSLTResult 类代码如下:
 1package cc.unmi.teststruts2.webcontext;
 2
 3import java.io.StringReader;
 4
 5import javax.xml.parsers.DocumentBuilder;
 6import javax.xml.parsers.DocumentBuilderFactory;
 7import javax.xml.transform.Source;
 8
 9import org.apache.struts2.views.xslt.XSLTResult;
10import org.xml.sax.InputSource;
11
12/**
13 * 自定义的 XSLTResult,默认会把字符串直接转换为 Document,保持原来的结构
14 * <br/> 这和 StringAdapter 的 ParseStringAsXML 是不同的,不会包上 <result> 节点
15 * parseStringAsXML 默认为 true
16 * @see org.apache.struts2.views.xslt.StringAdapter
17 * @author Unmi
18 * CreateTime: Apr 12, 2011
19 */
20@SuppressWarnings("serial")
21public class StringXSLTResult extends XSLTResult {
22
23    private boolean parseStringAsXML = true;
24
25    public void setParseStringAsXML(boolean parseStringAsXML) {
26        this.parseStringAsXML = parseStringAsXML;
27    }
28
29    @Override
30    protected Source getDOMSourceForStack(Object value) throws IllegalAccessException, InstantiationException {
31
32        //是字符串且 parseStringAsXML 为 true 时,直接转换为 org.w3c.dom.Document
33        //出现异常或其他条件时沿用传统的 XSLTResult 处理方式
34        if(parseStringAsXML && value instanceof String){
35            try {
36                DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
37                value = builder.parse(new InputSource(new StringReader((String)value)));
38            } catch (Exception e) {
39                //throw new IllegalAccessException("Can't cast value to Document type.");
40                return super.getDOMSourceForStack(value);
41            }           
42        }
43        
44        return super.getDOMSourceForStack(value);
45    }
46}

现在如何使用它呢,先要在 struts.xml 文件中配置:
 1<?xml version="1.0" encoding="UTF-8"?>
 2<!DOCTYPE struts PUBLIC
 3        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
 4        "http://struts.apache.org/dtds/struts-2.0.dtd">
 5
 6<struts>
 7
 8    <package name="unmi" namespace="/" extends="struts-default">
 9
10        <result-types>
11            <!-- 定义 StringXSLTResult, 为区别与内置的 xslt, 我们命名为 sxslt -->
12            <result-type name="sxslt" class="cc.unmi.teststruts2.webcontext.StringXSLTResult"/>
13        </result-types>
14
15        <action name="user" class="cc.unmi.teststruts2.action.UserAction">
16            <result type="sxslt"> <!-- 这里使用上面定义的 sxslt, 其他属性与 xslt 是一样的 -->
17                <param name="exposedValue">xmlString</param>
18                <param name="stylesheetLocation ">/xslt/user.xslt</param>
19                <param name="noCache">true</param>
20            </result>
21        </action>
22    </package>
23
24</struts>

现在 Action 中只需要向 xslt 直接输送字符串就行:
1public String execute(){
2    String xmlString = "<user><name>Unmi</name></user>"
3    Map<String, Object> contextMap = ActionContext.getContext().getContextMap();
4    contextMap.put("xmlString", xmlString);
5    return SUCCESS;
6}

在 /xslt/user.xslt 里,<user> 就是它所要处理 Document 的根节点了,没有额外的 <result>,所以 user.xslt 的内容写成:
 1<?xml version="1.0" encoding="UTF-8"?>
 2<xsl:stylesheet version="1.0"
 3    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 4
 5    <xsl:output method="xml" omit-xml-declaration="yes" />
 6
 7    <xsl:template match="/user">
 8        <xsl:value-of select="name"/>
 9    </xsl:template>
10
11</xsl:stylesheet>

上面显示出来的就是 Unmi 了。总之,记住了根节点不再是 <result> 了。以后碰到直接调用 Service 获得的是 XML String 的时候就可以使用这个自定义的 sxslt 结果了。

参考:1. Struts2 使用 XSLTResult 输出页面内容详解
           2. Struts2 使用 xslt 结果类型如何把字符串直接作为 Document 内容 永久链接 https://yanbin.blog/struts2-xslt-string-document-final/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。