XSLT插入兄弟如果它不存在 - 由于某种原因不能重新运行

时间:2015-06-17 17:02:32

标签: xml xslt xpath

我试图仅在元素不存在的情况下向元素添加兄弟元素。

这是我的XML:

<?xml version='1.0' encoding='UTF-8'?>
<domain xmlns="http://xmlns.oracle.com/weblogic/domain" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.oracle.com/weblogic/security/xacml http://xmlns.oracle.com/weblogic/security/xacml/1.0/xacml.xsd http://xmlns.oracle.com/weblogic/security/providers/passwordvalidator http://xmlns.oracle.com/weblogic/security/providers/passwordvalidator/1.0/passwordvalidator.xsd http://xmlns.oracle.com/weblogic/domain http://xmlns.oracle.com/weblogic/1.0/domain.xsd http://xmlns.oracle.com/weblogic/security http://xmlns.oracle.com/weblogic/1.0/security.xsd http://xmlns.oracle.com/weblogic/security/wls http://xmlns.oracle.com/weblogic/security/wls/1.0/wls.xsd">
  <security-configuration>
    <realm>
      <sec:authentication-provider xsi:type="wls:default-authenticatorType">
        <wls:use-retrieved-user-name-as-principal>true</wls:use-retrieved-user-name-as-principal>
      </sec:authentication-provider>
      <sec:authentication-provider xsi:type="wls:default-identity-asserterType">
        <sec:active-type>AuthenticatedUser</sec:active-type>
      </sec:authentication-provider>
    </realm>
  </security-configuration>
</domain>

所需的输出应为:

<domain xmlns="http://xmlns.oracle.com/weblogic/domain" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.oracle.com/weblogic/security/xacml http://xmlns.oracle.com/weblogic/security/xacml/1.0/xacml.xsd http://xmlns.oracle.com/weblogic/security/providers/passwordvalidator http://xmlns.oracle.com/weblogic/security/providers/passwordvalidator/1.0/passwordvalidator.xsd http://xmlns.oracle.com/weblogic/domain http://xmlns.oracle.com/weblogic/1.0/domain.xsd http://xmlns.oracle.com/weblogic/security http://xmlns.oracle.com/weblogic/1.0/security.xsd http://xmlns.oracle.com/weblogic/security/wls http://xmlns.oracle.com/weblogic/security/wls/1.0/wls.xsd">
  <security-configuration>
    <realm>
      <sec:authentication-provider xsi:type="wls:default-authenticatorType">
        <wls:use-retrieved-user-name-as-principal>true</wls:use-retrieved-user-name-as-principal>
      </sec:authentication-provider>
      <sec:authentication-provider xsi:type="wls:default-identity-asserterType">
        <sec:active-type>AuthenticatedUser</sec:active-type>
      </sec:authentication-provider>
   <!-- Just adding this element -->    
      <sec:authentication-provider xmlns:ext="http://xmlns.oracle.com/weblogic/security/extension" xsi:type="ext:session-authenticatorType">
        <sec:name>SessionAuthenticator</sec:name>
        <sec:control-flag>SUFFICIENT</sec:control-flag>
      </sec:authentication-provider>

    </realm>
  </security-configuration>
</domain>

这种转换需要重新运行,因此我只需添加新元素(如果它不存在)。

这是我尝试使用的XLST:

<xsl:stylesheet version="1.0" xmlns:bi="http://xmlns.oracle.com/weblogic/domain"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xmlns:sec="http://xmlns.oracle.com/weblogic/security"              
                xmlns:wls="http://xmlns.oracle.com/weblogic/security/wls">
<xsl:output method="xml" version="1.0" encoding='UTF-8' indent="yes" />
<xsl:strip-space elements="*"/>

<xsl:template match="@*|node()">
  <!-- Identity transform -->
  <xsl:copy>
    <xsl:apply-templates select="@*|node()" />
  </xsl:copy>
</xsl:template>  
<!-- match the existing child of realm -->
<xsl:template match="bi:realm/sec:authentication-provider[@xsi:type='wls:default-identity-asserterType']">
  <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>

  <!-- If the element doesn't exist already add it as a sibling -->
  <xsl:if test="not(bi:realm/sec:authentication-provider[@xsi:type='ext:session-authenticatorType'])">    
    <sec:authentication-provider xmlns:ext="http://xmlns.oracle.com/weblogic/security/extension" xsi:type="ext:session-authenticatorType">
      <sec:name>SessionAuthenticator</sec:name>
      <sec:control-flag>SUFFICIENT</sec:control-flag>
    </sec:authentication-provider>
  </xsl:if>
</xsl:template>

运行此转换时,会添加所需的元素。然而问题是这不可重新运行。每次运行时都会忽略检查是否存在新元素。有什么想法吗?

1 个答案:

答案 0 :(得分:2)

您的模板与sec:authentication-provider元素匹配:

match="bi:realm/sec:authentication-provider[...]"

因此,在模板中,上下文节点是匹配的sec:authentication-provider元素。因此,在执行测试时,您需要从该上下文继续。你目前的考试

test="not(bi:realm/sec:authentication-provider[@xsi:type='ext:session-authenticatorType'])"

仅在上下文节点是bi:realm的父节点时才有效,即bi:security-configuration。由于上下文节点是sec:authentication-provider元素,并且您想测试兄弟节点,因此您的测试应如下所示:

test="not(../sec:authentication-provider[@xsi:type='ext:session-authenticatorType'])"

在实践中,如果我没有弄错的话,你正在测试的兄弟姐妹总是来匹配的元素之后。因此,您可以使用following-sibling::代替../