0

我一直在寻找一种方法来检查 Web 应用程序部署描述符 (web.xml) 中是否存在特定的“servlet-mapping”,如果未找到则添加它,同时保持 XSLT 1.0 的架构有效性,但是,我'我会睁一只眼闭一只眼地试图弄清楚它并继续兜圈子,这可能会使它变得更加困难。

根据 Java Servlet 规范,“servlet-mapping”元素必须跟在“servlet”之后(如果存在),而后者又必须跟在“listener”元素之后(如果已定义),依此类推。

那么,仅当“servlet-mapping”不存在时,如何在所有其他“servlet”元素之后添加“servlet-mapping”元素。

这是一个配对的web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  version="2.5"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    <init-param>
      <param-name>debug</param-name>
      <param-value>0</param-value>
    </init-param>
    <init-param>
      <param-name>listings</param-name>
      <param-value>false</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet>
    <servlet-name>jsp</servlet-name>
    <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
    <init-param>
      <param-name>fork</param-name>
      <param-value>false</param-value>
    </init-param>
    <init-param>
      <param-name>xpoweredBy</param-name>
      <param-value>false</param-value>
    </init-param>
    <load-on-startup>3</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>/jsp/*</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.jsp</url-pattern>
  </servlet-mapping>
</web-app>

这是我的 XSLT,不幸的是,它会将“servlet-mapping”元素放在 web.xml 的开头,如果不存在的话:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:jee="http://java.sun.com/xml/ns/javaee"
        xmlns="http://java.sun.com/xml/ns/javaee">
        <xsl:output method="xml" encoding="UTF-8"/>

        <xsl:param name="version.jsp.servlet.name" select="'jsp'"/>
        <xsl:param name="version.jsp.url.pattern" select="'/jsp/*'"/>

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

        <xsl:template match="jee:web-app">
                <xsl:copy>
                        <xsl:apply-templates select="@*"/>

                        <xsl:if test="not(jee:servlet-mapping[jee:servlet-name=$version.jsp.servlet.name and jee:url-pattern=$version.jsp.url.pattern])">
                                <xsl:message>Adding jsp servlet-mapping</xsl:message>
                                <xsl:element name="servlet-mapping">
                                        <xsl:element name="servlet-name">
                                                <xsl:value-of select="$version.jsp.servlet.name"/>
                                        </xsl:element>
                                        <xsl:element name="url-pattern">
                                                <xsl:value-of select="$version.jsp.url.pattern"/>
                                        </xsl:element>
                                </xsl:element>
                        </xsl:if>

                        <xsl:apply-templates select="node()"/>
                </xsl:copy>
        </xsl:template>
</xsl:stylesheet>

我尝试在 XPath 表达式中使用“following-sibling”,但无济于事,如下所示:

not(jee:servlet[position()=last()]/following-sibling::jee:servlet-mapping[jee:servlet-name=$version.jsp.servlet.name and jee:url-pattern=$version.jsp.url.pattern])

我还需要在 XML 中添加一个“过滤器”元素,然后是一个“过滤器映射”元素,但是,在这种情况下,我显然需要在所有“图标”、“显示名称”、“描述”之后添加它们, “distributable”和“context-param”元素(如果它们存在的话)。

如果前面的必需元素完全存在,我将如何构造一个 XPath 表达式来解释它们?

4

2 回答 2

0

我建议使用这个:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:jee="http://java.sun.com/xml/ns/javaee"
        xmlns="http://java.sun.com/xml/ns/javaee"
        exclude-result-prefixes="jee">
  <xsl:output method="xml" encoding="UTF-8"/>

  <xsl:param name="version.jsp.servlet.name" select="'jsp'"/>
  <xsl:param name="version.jsp.url.pattern" select="'/jsp/*'"/>

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

  <xsl:template match="jee:servlet[last()]">
    <xsl:call-template name="Copy" />

    <xsl:if test="not(../jee:servlet-mapping
                        [jee:servlet-name = $version.jsp.servlet.name and
                         jee:url-pattern = $version.jsp.url.pattern])">
      <xsl:call-template name="ServletMapping" />
    </xsl:if>
  </xsl:template>

  <xsl:template name="ServletMapping">
    <servlet-mapping>
      <servlet-name>
        <xsl:value-of select="$version.jsp.servlet.name"/>
      </servlet-name>
      <url-pattern>
        <xsl:value-of select="$version.jsp.url.pattern"/>
      </url-pattern>
    </servlet-mapping>
  </xsl:template>
</xsl:stylesheet>
于 2013-03-14T18:57:07.017 回答
0

如果你把你 xsl:if 放在你的应用模板之后,它应该可以工作。

但也许添加这样的模板也可能对您有所帮助:

<!-- It's the last servlet of the input -->
<xsl:template match="jee:servlet[not(following-sibling::jee:servlet)]">
    <!-- First do as usual and copy the servlet -->
    <xsl:next-match/>
    <!-- Then test if you need to output some specific mapping -->
    <xsl:if test="not(jee:servlet-mapping[jee:servlet-name=$version.jsp.servlet.name and jee:url-pattern=$version.jsp.url.pattern])">
    ...
    </xsl:if>
 </xsl:template>

但是在您的问题中使用 position() 不能如您所愿,因为您需要“上下文中的最后一个 servlet”,而不是“仅当它是上下文中的最后一个元素时才使用 servlet”。我认为使用模板示例,您将能够解决“过滤器案例”。

如果您被 XSLT 1.0 困住,xsl:next-match 将无法工作。只需为您的通用模板命名(匹配 + 名称属性)并显式调用它而不是 xsl:next-match。

于 2013-03-14T18:01:19.810 回答