使用XSLT修改web.xml并保持架构有效性

时间:2013-03-14 03:28:26

标签: validation xslt xsd web.xml

我一直在寻找一种方法来检查Web应用程序部署描述符(web.xml)中是否存在特定的“servlet-mapping”,如果在使用XSLT 1.0维护Schema有效性时未找到则添加它,但是,我会睁大眼睛试图解决这个问题并继续进行,并且可能会让它变得更加困难。

根据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表达式中使用“follow-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中添加一个“filter”元素后跟一个“filter-mapping”元素,但是,在这种情况下,我显然需要在所有“icon”,“display-name”之后添加它们,“描述“,”distributable“和”context-param“元素,如果它们存在的话。

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

2 个答案:

答案 0 :(得分:0)

如果你把xsl:if放在你的apply-templates之后,它应该可以工作。

但也许添加这样的模板也可以帮到你:

<!-- 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。

答案 1 :(得分: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>