此樣式表可用於「建立」規則, 並顯示如何從外部應用程式中建立的項目來建立 eDirectory 使用者。 此範例的概念基礎是先在「人力資源」資料庫中建立新僱用的人員,再於網路上加以建立。 這需要使用者的名和姓,且會在 eDirectory 網路樹中產生唯一的 CN。 雖然 eDirectory 要求 CN 只在容器中是唯一的,此樣式表仍會確保其在 eDirectory 網路樹的所有容器中都是唯一的。
<?xml version="1.0" encoding="ISO-8859-1"?> <!-- This stylesheet is an example of how to replace a create rule with an XSLT stylesheet and that creates the User name from the Surname and given Name attributes --> <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:query="http://www.novell.com/nxsl/java/com.novell.nds.dirxml.driver. XdsQueryProcessor" > <!-- This is for testing the stylesheet outside of Identity Manager so things are pretty to look at --> <xsl:strip-space elements="*"/> <xsl:preserve-space elements="value,component"/> <xsl:output method="xml" indent="yes"/> <!-- Identity Manager always passes two stylesheet parameters to an XSLT rule: an inbound and outbound query processor --> <xsl:param name="srcQueryProcessor"/> <xsl:param name="destQueryProcessor"/> <!-- match <add> elements --> <xsl:template match="add"> <!-- ensure we have required NDS attributes we need for the name --> <xsl:if test="add-attr[@attr-name=’Surname’] and add-attr[@attr-name=’Given Name’]"> <!-- copy the add through --> <xsl:copy> <!-- copy any attributes through except for the src-dn --> <!-- we’ll construct the src-dn below so that the placement rule will work --> <xsl:apply-templates select="@*[string(.) != ’src-dn’]"/> <!-- call a template to construct the object name and place the result in a variable --> <xsl:variable name="object-name"> <xsl:call-template name="create-object-name"/> </xsl:variable> <!-- now create the src-dn attribute with the created name --> <xsl:attribute name="src-dn"> <xsl:variable name="prefix"> <xsl:call-template name="get-dn-prefix"> <xsl:with-param name="src-dn" select="string(@src-dn)"/> </xsl:call-template> </xsl:variable> <xsl:value-of select="concat($prefix,’\’,$object-name)"/> </xsl:attribute> <!-- if we have a "CN" attribute, set it to the constructed name --> <xsl:if test="./add-attr[@attr-name=’CN’]"> <add-attr attr-name="CN"> <value type="string"><xsl:value-of select="$object-name"/></value> </add-attr> </xsl:if> <!-- copy the rest of the stuff through, except for what we have already copied --> <xsl:apply-templates select="*[name() != ’add-attr’ or @attr-name != ’CN’] | comment() | processing-instruction() | text()"/> <!-- add a <password> element --> <xsl:call-template name="create-password"/> </xsl:copy> </xsl:if> <!-- if the xsl:if fails, it means we don’t have all the required attributes so we won’t copy the add through, and the create rule will veto the add --> </xsl:template> <!-- get-dn-prefix places the part of the passed dn that precedes the --> <!-- last occurrance of ’\’ in the passed dn in a result tree fragment --> <!-- meaning that it can be used to assign a variable value --> <xsl:template name="get-dn-prefix" xmlns:jstring="http://www.novell.com/nxsl/java/java.lang.String"> <xsl:param name="src-dn"/> <!-- use java string stuff to make this much easier --> <xsl:variable name="dn" select="jstring:new($src-dn)"/> <xsl:variable name="index" select="jstring:lastIndexOf($dn,’\’)"/> <xsl:if test="$index != -1"> <xsl:value-of select="jstring:substring($dn,0,$index)"/> </xsl:if> </xsl:template> <!-- create-object-name creates a name for the user object and places the --> <!-- result in a result tree fragment --> <xsl:template name="create-object-name"> <!-- first try is first initial followed by surname --> <xsl:variable name="given-name" select="add-attr[@attr-name=’Given Name’]/value"/> <xsl:variable name="surname" select="add-attr[@attr-name=’Surname’]/value"/> <xsl:variable name="prefix" select="substring($given-name,1,1)"/> <xsl:variable name="object-name" select="concat($prefix,$surname)"/> <!-- then see if name already exists in NDS --> <xsl:variable name="exists"> <xsl:call-template name="query-object-name"> <xsl:with-param name="object-name" select="$object-name"/> </xsl:call-template> </xsl:variable> <!-- if exists, then try 1st fallback, else return result --> <xsl:choose> <xsl:when test="$exists != ’’"> <xsl:call-template name="create-object-name-2"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$object-name"/> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- create-object-name-2 is the first fallback if the name created by --> <!-- create-object-name already exists --> <xsl:template name="create-object-name-2"> <!-- first try is first name followed by surname --> <xsl:variable name="given-name" select="add-attr[@attr-name=’Given Name’]/value"/> <xsl:variable name="surname" select="add-attr[@attr-name=’Surname’]/value"/> <xsl:variable name="object-name" select="concat($given-name,$surname)"/> <!-- then see if name already exists in NDS --> <xsl:variable name="exists"> <xsl:call-template name="query-object-name"> <xsl:with-param name="object-name" select="$object-name"/> </xsl:call-template> </xsl:variable> <!-- if exists, then try last fallback, else return result --> <xsl:choose> <xsl:when test="$exists != ’’"> <xsl:call-template name="create-object-name-fallback"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$object-name"/> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- create-object-name-fallback recursively tries a name created by --> <!-- concatenating the surname and a count until NDS doesn’t find --> <!-- the name. There is a danger of infinite recursion, but only if --> <!-- there is a bug in NDS --> <xsl:template name="create-object-name-fallback"> <xsl:param name="count" select="1"/> <!-- construct the a name based on the surname and a count --> <xsl:variable name="surname" select="add-attr[@attr-name=’Surname’]/value"/> <xsl:variable name="object-name" select="concat($surname,’-’,$count)"/> <!-- see if it exists in NDS --> <xsl:variable name="exists"> <xsl:call-template name="query-object-name"> <xsl:with-param name="object-name" select="$object-name"/> </xsl:call-template> </xsl:variable> <!-- if exists, then try again recursively, else return result --> <xsl:choose> <xsl:when test="$exists != ’’"> <xsl:call-template name="create-object-name-fallback"> <xsl:with-param name="count" select="$count + 1"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$object-name"/> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- query object name queries NDS for the passed object-name. Ideally, this would --> <!-- not depend on "CN": to do this, add another parameter that is the name of the --> <!-- naming attribute. --> <xsl:template name="query-object-name"> <xsl:param name="object-name"/> <!-- build an xds query as a result tree fragment --> <xsl:variable name="query"> <nds ndsversion="8.5" dtdversion="1.0"> <input> <query> <search-class class-name="{ancestor-or-self::add/@class-name}"/> <!-- NOTE: depends on CN being the naming attribute --> <search-attr attr-name="CN"> <value><xsl:value-of select="$object-name"/></value> </search-attr> <!-- put an empty read attribute in so that we don’t get the whole object back --> <read-attr/> </query> </input> </nds> </xsl:variable> <!-- query NDS --> <xsl:variable name="result" select="query:query($destQueryProcessor,$query)"/> <!-- return an empty or non-empty result tree fragment depending on result of query --> <xsl:value-of select="$result//instance"/> </xsl:template> <!-- create an initial password --> <xsl:template name="create-password"> <password> <xsl:value-of select="concat(add-attr[@attr-name=’Surname’]/value,’-’,add-attr[@attr-name=’CN’]/value)"/> </password> </xsl:template> <!-- identity transform for everything we don’t want to mess with --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:transform>