<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.lefebvre-sarrut.eu/ns/xmlfirst" xmlns:xfRes="http://www.lefebvre-sarrut.eu/ns/xmlfirst/ecm/resources" xmlns:ecm="http://www.lefebvre-sarrut.eu/ns/xmlfirst/ecm" xmlns:xfe="http://www.lefebvre-sarrut.eu/ns/xmlfirst/xmlEditor" xmlns:fichesGB_FP="http://www.lefebvre-sarrut.eu/ns/el/fichesGB_FP" xmlns="http://www.w3.org/1999/xhtml" xpath-default-namespace="http://www.lefebvre-sarrut.eu/ns/xmlfirst" exclude-result-prefixes="#all" version="3.0"> <xsl:import href="EL_TEE_practiceNoteAssemblee.htmlSimplePreview.xsl"/> <xsl:import href="fichePratique.htmlSimplePreview.xsl"/> <!--<xsl:import href="el_ficheMT.htmlSimplePreview.xsl"/> FIXME : impossible d'importer 2 fois un preview à cause des variables dupliquée (notamment xfe:conf.uri !!!) => pour le moment il n'y a que des fichePratique assemblée, donc c'est bon --> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>Generate a HTML proofing for EE type "EL_TEE_practiceNoteAssemblee"</xd:p> </xd:desc> </xd:doc> <xsl:param name="xfRes:debug" select="false()" as="xs:boolean"/> <xsl:param name="xfRes:log.uri" select="resolve-uri('log/', base-uri(/))" as="xs:string"/> <xsl:param name="xfRes:css.uri" select="'../../../main/web-resources/css/EL_TEE_practiceNoteAssemblee.htmlProofing.css'" as="xs:string"/> <xsl:param name="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing_skipAggregation" select="false()" as="xs:boolean"/> <!--indent="no" is important for xspec diff--> <xsl:output method="xhtml" indent="no"/> <!--+==================================================+ | INIT. | +==================================================+--> <xsl:template match="/"> <xsl:apply-templates select="." mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing"/> </xsl:template> <!--==================================================--> <!--MAIN--> <!--==================================================--> <!--Driver--> <xsl:template match="/" mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing"> <!--resolve referencenNode--> <xsl:variable name="step" as="document-node()"> <xsl:choose> <xsl:when test="$xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing_skipAggregation"> <xsl:sequence select="."/> </xsl:when> <xsl:otherwise> <xsl:document> <xsl:apply-templates select="." mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing-step1"/> </xsl:document> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:if test="$xfRes:debug"> <xsl:variable name="step.log.uri" select="resolve-uri('EL_TEE_practiceNoteAssemblee.htmlProofing.step1.xml', $xfRes:log.uri)" as="xs:anyURI"/> <xsl:message>[INFO] writing <xsl:value-of select="$step.log.uri"/></xsl:message> <xsl:result-document href="{$step.log.uri}"> <xsl:sequence select="$step"/> </xsl:result-document> </xsl:if> <!--Adapt XML content--> <xsl:variable name="step" as="document-node()"> <xsl:document> <xsl:apply-templates select="$step" mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing-step2"/> </xsl:document> </xsl:variable> <xsl:if test="$xfRes:debug"> <xsl:variable name="step.log.uri" select="resolve-uri('EL_TEE_practiceNoteAssemblee.htmlProofing.step2.xml', $xfRes:log.uri)" as="xs:anyURI"/> <xsl:message>[INFO] writing <xsl:value-of select="$step.log.uri"/></xsl:message> <xsl:result-document href="{$step.log.uri}"> <xsl:sequence select="$step"/> </xsl:result-document> </xsl:if> <!--Transform to HTML--> <!--Use the simple preview of this tree, referenceNode template will be overrided to transform ther referenced EE to html--> <xsl:apply-templates select="$step" mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlSimplePreview"/> </xsl:template> <!--=============================--> <!--STEP-1 : resolve--> <!--=============================--> <xsl:template match="referenceNode/ref" mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing-step1"> <xsl:variable name="doc.uri" select="concat($ecm:ee.url.begin, @xf:targetResId)" as="xs:string"/> <xsl:copy> <xsl:apply-templates select="@*" mode="#current"/> <xsl:choose> <xsl:when test="doc-available($doc.uri)"> <xsl:apply-templates select="doc($doc.uri)" mode="#current"/> </xsl:when> <xsl:otherwise> <xsl:copy> <html:p class="ecm_error">[ERROR] EE <xsl:value-of select="$doc.uri"/> is not available !</html:p> <html:p class="ecm_debug"> <xsl:choose> <xsl:when test="unparsed-text-available($doc.uri)"> <p>unparsed-text-available :</p> <textarea rows="10" cols="50"> <xsl:value-of select="unparsed-text($doc.uri)"/> </textarea> </xsl:when> <xsl:otherwise> <p>unparsed-text is not available</p> </xsl:otherwise> </xsl:choose> </html:p> </xsl:copy> </xsl:otherwise> </xsl:choose> </xsl:copy> </xsl:template> <xsl:template match="node() | @*" mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing-step1"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> <!--=============================--> <!--STEP-2 : adapt xml content --> <!--=============================--> <!--=====================--> <!--Surcharge Tifp--> <!--=====================--> <!--SIEGEL-167 : surcharge de Tifp en utilisant le systemTitle du referenceNode si celui-ci est renseigné--> <xsl:template match="referenceNode/ref/editorialEntity/body/contentNode/content/fichesGB_FP:FP/fichesGB_FP:Tifp[1]" mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing-step2"> <xsl:variable name="referenceNode.systemTitle.div" select="ancestor::referenceNode[1]/metadata/meta[@code = 'systemTitle']/value[@as = 'element(html:div)']/html:div[1]" as="element(html:div)?"/> <xsl:choose> <xsl:when test="not(matches(string($referenceNode.systemTitle.div), concat('^', $els:regAnySpace,'*$')))"> <div class="Tifp"> <xsl:message use-when="false()">[DEBUG] SIEGEL-167.1 : surcharge Tifp</xsl:message> <xsl:copy-of select="$referenceNode.systemTitle.div/node()"/> </div> </xsl:when> <xsl:otherwise> <xsl:next-match/> </xsl:otherwise> </xsl:choose> </xsl:template> <!--=====================--> <!--Surcharge OBS--> <!--=====================--> <!--SIEGEL-167 : Si EL_META_conserveObservation=false sur le referenceNode, alors : dans l'editorialEntity référencée il faut remplacer le contenu "body/contentNode/content/FP/OBS[1]" par le contenu de la méta EL_META_surchargeObservation si elle existe, sinon on supprime cet élément. ERRATUM : Lors du remplacement : 1) Si OBS n'existe pas : - Si PAPL exite : ajouter "OBS de surcharge" avant PAPL[last()] - Si PAPL n'existe pas : ajouter "OBS de surcharge" en dernier élément sous FP 2) Si EL_META_surchargeObservation contient un titre de l'observation (1er <p> avec <strong>) alors il vient remplacer OBS/Tiobs (NB : dans tous les cas on remplace tout ou rien) --> <!--CAS 1 : surcharge demandée + pas OBS ni PAPL : ajout OBS fin de FP--> <xsl:template match="referenceNode/ref/editorialEntity/body/contentNode/content/fichesGB_FP:FP [xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.get-EL_META_conserveObservation(.) = 'false'] [not(fichesGB_FP:OBS)][not(fichesGB_FP:PAPL)] /*[last()]" priority="1" mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing-step2"> <xsl:next-match/> <xsl:message use-when="false()">[DEBUG] SIEGEL-167.2 : CAS 1</xsl:message> <xsl:call-template name="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.makeObservationSurcharge"/> </xsl:template> <!--CAS 2 : surcharge demandée + OBS existe : on le remplace (par rien éventuellement)--> <xsl:template match="referenceNode/ref/editorialEntity/body/contentNode/content/fichesGB_FP:FP/fichesGB_FP:OBS[1] [xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.get-EL_META_conserveObservation(.) = 'false']" mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing-step2"> <xsl:message use-when="false()">[DEBUG] SIEGEL-167.2 : CAS 2</xsl:message> <xsl:call-template name="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.makeObservationSurcharge"/> </xsl:template> <!--CAS 3 : surcharge demandée + OBS n'existe pas mais PAPL existe : ajout OBS avant 1er PAPL--> <xsl:template match="referenceNode/ref/editorialEntity/body/contentNode/content/fichesGB_FP:FP[not(fichesGB_FP:OBS)]/fichesGB_FP:PAPL[1] [xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.get-EL_META_conserveObservation(.) = 'false']" mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing-step2" priority="1"> <xsl:message use-when="false()">[DEBUG] SIEGEL-167.2 : CAS 3</xsl:message> <xsl:call-template name="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.makeObservationSurcharge"/> <xsl:next-match/> </xsl:template> <!--WARNING : si Tiobs est directement sous FP et non dans OBS--> <xsl:template match="referenceNode/ref/editorialEntity/body/contentNode/content/fichesGB_FP:FP/fichesGB_FP:Tiobs [xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.get-EL_META_conserveObservation(.) = 'false']" mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing-step2"> <xsl:message use-when="false()">[DEBUG] SIEGEL-167.2 : Warning</xsl:message> <div class="ecm_error"> <p style="color:inherit;">[ERROR] Le Tiobs ci-dessous est mal placé, il devrait être à l'intérieur de OBS, la surcharge méta de l'observation ne sera pas correcte</p> </div> <xsl:next-match/> </xsl:template> <xsl:function name="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.get-EL_META_surchargeObservation" as="element(html:div)?"> <xsl:param name="e" as="element()"/> <xsl:sequence select="$e/ancestor::referenceNode[1]/metadata/meta[@code = 'EL_META_surchargeObservation']/value[@as = 'element(html:div)']/html:div"/> </xsl:function> <xsl:function name="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.get-EL_META_conserveObservation" as="xs:string?"> <xsl:param name="e" as="element()"/> <xsl:sequence select="$e/ancestor::referenceNode[1]/metadata/meta[@code = 'EL_META_conserveObservation']/value[@as = 'xs:boolean']/text()[1]"/> </xsl:function> <xsl:template name="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.makeObservationSurcharge"> <xsl:param name="EL_META_surchargeObservation.content" select="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.get-EL_META_surchargeObservation(.)/node()[not(self::text()[els:is-empty-or-whitespace(.)])]" as="item()*"/> <xsl:if test="count($EL_META_surchargeObservation.content) != 0"> <OBS xmlns="http://www.lefebvre-sarrut.eu/ns/el/fichesGB_FP"> <xsl:variable name="Tiobs" select="$EL_META_surchargeObservation.content/self::*[xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.isHtmlTiobs(.)]" as="element()?"/> <xsl:if test="exists($Tiobs)"> <Tiobs> <xsl:sequence select="$Tiobs/html:strong/node()"/> </Tiobs> </xsl:if> <xsl:sequence select="$EL_META_surchargeObservation.content except $Tiobs"/> </OBS> </xsl:if> </xsl:template> <xsl:function name="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.isHtmlTiobs" as="xs:boolean"> <xsl:param name="e" as="element()"/> <xsl:sequence select="boolean($e/self::html:p[1][not(text()[normalize-space(.) != ''])][count(*)= 1 and html:strong])"/> </xsl:function> <!--=====================--> <!--Surcharge Resume--> <!--=====================--> <!--SIEGEL-167 : Si EL_META_conserveResume=false sur le referenceNode, alors : dans l'editorialEntity référencée il faut remplacer le contenu "body/contentNode/content/FP/INTROFP[1]" par le contenu de la méta EL_META_surchargeResume si elle existe, sinon on supprime cet élément. ERRATUM : si INTROFP n'existe pas et qu'il y a une surcharge, on le rajoute sous Tifp --> <xsl:template match="referenceNode/ref/editorialEntity/body/contentNode/content/fichesGB_FP:FP [xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.get-EL_META_conserveResume(.) = 'false'] [not(fichesGB_FP:INTROFP)] /fichesGB_FP:Tifp[1]" priority="1" mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing-step2"> <xsl:next-match/> <xsl:message use-when="false()">[DEBUG] SIEGEL-167.3 : surcharge résumé - CAS 1</xsl:message> <xsl:call-template name="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.makeResumeSurcharge"/> </xsl:template> <xsl:template match="referenceNode/ref/editorialEntity/body/contentNode/content/fichesGB_FP:FP/fichesGB_FP:INTROFP[1] [xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.get-EL_META_conserveResume(.) = 'false']" mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing-step2"> <xsl:call-template name="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.makeResumeSurcharge"/> <xsl:message use-when="false()">[DEBUG] SIEGEL-167.3 : surcharge résumé - CAS 2</xsl:message> </xsl:template> <xsl:function name="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.get-EL_META_conserveResume" as="xs:string?"> <xsl:param name="e" as="element()"/> <xsl:sequence select="$e/ancestor::referenceNode[1]/metadata/meta[@code = 'EL_META_conserveResume']/value[@as = 'xs:boolean']/text()[1]"/> </xsl:function> <xsl:function name="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.get-EL_META_surchargeResume" as="element(html:div)?"> <xsl:param name="e" as="element()"/> <xsl:sequence select="$e/ancestor::referenceNode[1]/metadata/meta[@code = 'EL_META_surchargeResume']/value[@as = 'element(html:div)']/html:div"/> </xsl:function> <xsl:template name="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.makeResumeSurcharge"> <xsl:param name="EL_META_surchargeResume.content" select="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing.get-EL_META_surchargeResume(.)/node()[not(self::text()[els:is-empty-or-whitespace(.)])]" as="item()*"/> <xsl:if test="count($EL_META_surchargeResume.content) != 0"> <INTROFP xmlns="http://www.lefebvre-sarrut.eu/ns/el/fichesGB_FP"> <xsl:sequence select="$EL_META_surchargeResume.content"/> </INTROFP> </xsl:if> </xsl:template> <!--=====================--> <!--Surcharge PAPL--> <!--=====================--> <!--SIEGEL-167 : Si EL_META_conservePAPL=false sur le referenceNode, alors : dans l'editorialEntity référencée on supprime tous les "body/contentNode/content/FP/PAPL" --> <xsl:template match="referenceNode/ref/editorialEntity/body/contentNode/content/fichesGB_FP:FP/fichesGB_FP:PAPL" mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing-step2"> <xsl:variable name="EL_META_conservePAPL" select="ancestor::referenceNode[1]/metadata/meta[@code = 'EL_META_conservePAPL']/value[@as = 'xs:boolean']/text()[1]" as="xs:string?"/> <xsl:choose> <xsl:when test="$EL_META_conservePAPL = 'false'"> <xsl:message use-when="false()">[DEBUG] SIEGEL-167.4 : EL_META_conservePAPL=false</xsl:message> <!--PAPL deleted --> </xsl:when> <xsl:otherwise> <xsl:next-match/> </xsl:otherwise> </xsl:choose> </xsl:template> <!--=====================--> <!--Surcharge REFPRINC--> <!--=====================--> <!--SIEGEL-167 : Si EL_META_conserveRefPrincipale=false sur le referenceNode, alors : dans l'editorialEntity référencée on supprime tous les "body/contentNode/content/FP/REFPRINC" --> <xsl:template match="referenceNode/ref/editorialEntity/body/contentNode/content/fichesGB_FP:FP/fichesGB_FP:REFPRINC" mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing-step2"> <xsl:variable name="EL_META_conserveRefPrincipale" select="ancestor::referenceNode[1]/metadata/meta[@code = 'EL_META_conserveRefPrincipale']/value[@as = 'xs:boolean']/text()[1]" as="xs:string?"/> <xsl:choose> <xsl:when test="$EL_META_conserveRefPrincipale = 'false'"> <xsl:message use-when="false()">[DEBUG] SIEGEL-167.5 : EL_META_conserveRefPrincipale=false</xsl:message> <!--REFPRINC deleted--> </xsl:when> <xsl:otherwise> <xsl:next-match/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="node() | @*" mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlProofing-step2"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> <!--=============================--> <!--STEP-3 : transform to HTML --> <!--=============================--> <!-- mode xfRes:EL_TEE_practiceNoteAssemblee.htmlSimplePreview, cf.EL_TEE_practiceNoteAssemblee.htmlSimplePreview.xsl EL_TEE_practiceNoteAssemblee.htmlSimplePreview.xsl is uses mode "xfRes:TEE_tree.default.htmlSimplePreview" So overriden rules will be applied on this mode --> <!--Adding debug informations--> <xsl:template match="body" mode="xfRes:TEE_tree.default.htmlSimplePreview"> <!--<body>--> <xsl:call-template name="xfRes:htmlPreview.addDebugInfo"/> <ul> <xsl:apply-templates mode="#current"/> </ul> <!--</body>--> </xsl:template> <!--Override referenceNode template of the original simple preview of this tree--> <xsl:template match="referenceNode" mode="xfRes:TEE_tree.default.htmlSimplePreview"> <li class="referenceNode"> <!--DO NOT APPLY VERBALIZATION HERE--> <!--<xsl:apply-templates select="(verbalization, ref)[1]" mode="#current"/>--> <xsl:choose> <xsl:when test="ref/editorialEntity"> <xsl:variable name="editorialEntity.doc" as="document-node()"> <xsl:document> <xsl:sequence select="ref/editorialEntity"/> </xsl:document> </xsl:variable> <xsl:variable name="TEE.code" select="$editorialEntity.doc/editorialEntity/@code" as="xs:string?"/> <xsl:variable name="referenceNode.ee.html" as="element()"> <div> <!--just used as variable container--> <xsl:choose> <xsl:when test="$TEE.code = 'EL_TEE_fichePratique'"> <xsl:apply-templates select="$editorialEntity.doc" mode="xfRes:EL_TEE_fichePratique.htmlSimplePreview"/> </xsl:when> <xsl:otherwise> <p class="ecm_error">EE code="<xsl:value-of select="$editorialEntity.doc/editorialEntity/@code"/>" unexpected here</p> <xsl:apply-templates select="$editorialEntity.doc" mode="xfRes:TEE_text.default.htmlSimplePreview"/> </xsl:otherwise> </xsl:choose> </div> </xsl:variable> <div class="ecm-aggregate"> <xsl:choose> <xsl:when test="$referenceNode.ee.html//html:body"> <xsl:sequence select="$referenceNode.ee.html//html:body/*"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="$referenceNode.ee.html/html:div/*"/> </xsl:otherwise> </xsl:choose> </div> </xsl:when> <xsl:otherwise> <!--display resolution error message--> <xsl:apply-templates select="ref/*" mode="#current"/> <xsl:apply-templates select="(verbalization, ref)[1]" mode="#current"/> </xsl:otherwise> </xsl:choose> </li> </xsl:template> <xsl:template match="html:*" mode="xfRes:TEE_tree.default.htmlSimplePreview"> <xsl:element name="{local-name()}"> <xsl:copy-of select="@*"/> <xsl:apply-templates mode="#current"/> </xsl:element> </xsl:template> <!--Override XFE conversion : keep html as is--> <!--Some html chunk from html meta has been added to the content on step 2--> <xsl:template match="html:*" mode="xfe:xml2html_annotations xfe:xml2html_main"> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:apply-templates mode="#current"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.lefebvre-sarrut.eu/ns/xmlfirst" xmlns:ecm="http://www.lefebvre-sarrut.eu/ns/xmlfirst/ecm" xmlns:xfRes="http://www.lefebvre-sarrut.eu/ns/xmlfirst/ecm/resources" xmlns="http://www.w3.org/1999/xhtml" xpath-default-namespace="http://www.lefebvre-sarrut.eu/ns/xmlfirst" exclude-result-prefixes="#all" version="3.0"> <!--<xsl:import href="_common/el2html.xsl"/>--> <xsl:import href="../_common/TEE_tree.default.htmlSimplePreview.xsl"/> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>Generate a HTML simple preview for EE type "EL_TEE_practiceNoteAssemblee"</xd:p> <xd:p>Import de "default tree preview", qui va être surchargée ici pour ajouter le titre depuis la méta ELS_META_titreEE</xd:p> </xd:desc> </xd:doc> <!--indent="no" is important for xspec diff--> <xsl:output method="xhtml" indent="no"/> <!--base-uri est perdu à cause du xsl:document dans le step 1, on surcharge sa valeur ici--> <xsl:param name="xfRes:baseUri" select="base-uri()" as="xs:anyURI"/> <!--==================================================--> <!--INIT--> <!--==================================================--> <!--No modes for standalone execution--> <xsl:template match="/"> <xsl:apply-templates select="." mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlSimplePreview"/> </xsl:template> <!--==================================================--> <!--MAIN--> <!--==================================================--> <xsl:template match="/" mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlSimplePreview"> <xsl:variable name="step" as="document-node()"> <xsl:document> <xsl:apply-templates select="." mode="xfRes:TEE_tree.default.htmlSimplePreview"/> </xsl:document> </xsl:variable> <!--Au step2 on a besoin de l'EE pour récupérer "ELS_META_titreEE"--> <xsl:variable name="editorialEntity" select="editorialEntity" as="element()"/> <xsl:apply-templates select="$step" mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlSimplePreview.step2"> <xsl:with-param name="editorialEntity" select="$editorialEntity" as="element()" tunnel="yes"/> </xsl:apply-templates> </xsl:template> <!--======--> <!-- MODE xfRes:TEE_tree.default.htmlSimplePreview--> <!--======--> <!--cf. import--> <!--Surcharge sur contentNode--> <xsl:template match="contentNode/content/*" mode="xfRes:TEE_tree.default.htmlSimplePreview"> <xsl:apply-templates select="node()" mode="#current"/> </xsl:template> <!--======--> <!-- MODE xfRes:EL_TEE_practiceNoteAssemblee.htmlSimplePreview.step2--> <!--======--> <!--Ajout du titre de la fiche au début du body--> <xsl:template match="html:body/*[1]" mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlSimplePreview.step2" priority="1"> <xsl:param name="editorialEntity" as="element()" tunnel="yes"/> <h1 class="Titrepa"> <xsl:apply-templates select="$editorialEntity/metadata/meta[@code = 'ELS_META_titreEE']/value/html:div/node()" mode="#current"/> </h1> <xsl:next-match/> </xsl:template> <xsl:template match="node() | @*" mode="xfRes:EL_TEE_practiceNoteAssemblee.htmlSimplePreview.step2"> <xsl:copy copy-namespaces="no"> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.lefebvre-sarrut.eu/ns/xmlfirst" xmlns:ecm="http://www.lefebvre-sarrut.eu/ns/xmlfirst/ecm" xmlns:xfRes="http://www.lefebvre-sarrut.eu/ns/xmlfirst/ecm/resources" xmlns="http://www.w3.org/1999/xhtml" xpath-default-namespace="http://www.lefebvre-sarrut.eu/ns/xmlfirst" exclude-result-prefixes="#all" version="3.0"> <xsl:import href="xslLib:/xslLib/xml2simpleHtml.xsl"/> <xsl:import href="../_common/TEE_text.html.default.htmlSimplePreview.xsl"/> <xsl:import href="../_common/xf-common.htmlPreview.xsl"/> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>Generate a HTML simple preview for EE type tree.</xd:p> <xd:p>This xslt is not able to display contentNode properly, import from another xslt that knows how to display sepcific contentNode</xd:p> </xd:desc> </xd:doc> <!--indent="no" is important for xspec diff--> <xsl:output method="xhtml" indent="no"/> <!--+==================================================+ | INIT. | +==================================================+--> <!--No modes for standalone execution--> <xsl:template match="/"> <xsl:apply-templates select="." mode="xfRes:TEE_tree.default.htmlSimplePreview"/> </xsl:template> <!--Mode xfRes:htmlSimplePreview for using from insertMetaInsideBody.xsl--> <xsl:template match="/" mode="xfRes:htmlSimplePreview"> <xsl:apply-templates select="." mode="xfRes:TEE_tree.default.htmlSimplePreview"/> </xsl:template> <!--+==================================================+ | MAIN | +==================================================+--> <xsl:template match="/" mode="xfRes:TEE_tree.default.htmlSimplePreview"> <html> <xsl:call-template name="xfRes:htmlPreview.makeHtmlHead"/> <body> <xsl:call-template name="xfRes:htmlPreview.addDebugInfo"/> <xsl:apply-templates select="editorialEntity" mode="#current"/> </body> </html> </xsl:template> <xsl:template match="editorialEntity" mode="xfRes:TEE_tree.default.htmlSimplePreview"> <xsl:apply-templates select="metadata/meta[@code = 'systemTitle']" mode="#current"/> <xsl:apply-templates select="body" mode="#current"/> </xsl:template> <xsl:template match="editorialEntity/metadata/meta[@code = 'systemTitle']" mode="xfRes:TEE_tree.default.htmlSimplePreview"> <!--FIXME SIEGEL-492: missing EE title as common behaviour ?--> <!--<div class="systemTitle level-{count(ancestor::editorialEntity)}"> <xsl:variable name="editorialEntity" select="../../self::editorialEntity" as="element(editorialEntity)"/> <xsl:apply-templates select="$editorialEntity/@xf:id" mode="#current"/> <xsl:variable name="referenceNode" select="$editorialEntity/parent::ref/parent::referenceNode" as="element(referenceNode)?"/> <xsl:choose> <xsl:when test="exists($referenceNode)"> <xsl:variable name="referenceNode.systemTitle.value" select="xf:getMeta($referenceNode, 'systemTitle')/xf:getMetaValueContent(.)" as="item()*"/> <xsl:choose> <xsl:when test="not(els:is-empty-or-whitespace($referenceNode.systemTitle.value))"> <xsl:sequence select="$referenceNode.systemTitle.value/node()"/> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="value/html:div/node()" mode="#current"/> </xsl:otherwise> </xsl:choose> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="value/html:div/node()" mode="#current"/> </xsl:otherwise> </xsl:choose> </div>--> </xsl:template> <xsl:template match="body" mode="xfRes:TEE_tree.default.htmlSimplePreview"> <ul> <xsl:apply-templates mode="#current"/> </ul> </xsl:template> <xsl:template match="structuralNode" mode="xfRes:TEE_tree.default.htmlSimplePreview"> <xsl:variable name="structuralNode.level" select="count(ancestor::structuralNode) + 1" as="xs:integer"/> <xsl:variable name="htmlElement.level" select="if($structuralNode.level le 6) then($structuralNode.level) else(6)" as="xs:integer"/> <xsl:variable name="htmlElement.name" select="concat('h', $htmlElement.level)" as="xs:string"/> <xsl:variable name="title.div" as="node()*"> <xsl:apply-templates select="title/html:div" mode="#current"/> </xsl:variable> <li class="structuralNode level-{$structuralNode.level}"> <xsl:apply-templates select="@xf:id" mode="#current"/> <xsl:element name="{$htmlElement.name}"> <xsl:choose> <xsl:when test="normalize-space(string($title.div)) != ''"> <xsl:copy-of select="$title.div/node()"/> </xsl:when> <xsl:otherwise> <xsl:text>[NO TITLE]</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:element> <xsl:if test="* except (metadata | title)"> <ul> <xsl:apply-templates select="* except (metadata | title)" mode="#current"/> </ul> </xsl:if> </li> </xsl:template> <xsl:template match="queryNode" mode="xfRes:TEE_tree.default.htmlSimplePreview"> <li class="queryNode"> <xsl:text>[ERROR][queryNode] TODO</xsl:text> </li> </xsl:template> <xsl:template match="referenceNode" mode="xfRes:TEE_tree.default.htmlSimplePreview"> <li class="referenceNode"> <xsl:apply-templates select="@xf:id" mode="#current"/> <xsl:variable name="systemTitle.value" select="xf:getMeta(., 'systemTitle')/xf:getMetaValueContent(.)" as="item()*"/> <xsl:variable name="referenceNode.title" as="item()*"> <xsl:choose> <xsl:when test="not(els:is-empty-or-whitespace($systemTitle.value))"> <xsl:sequence select="$systemTitle.value/node()"/> </xsl:when> <xsl:when test="not(els:is-empty-or-whitespace(verbalization))"> <xsl:apply-templates select="verbalization" mode="#current"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="(ref/@xf:targetResId, '[ERROR] No verbalization or id found')[1]"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:apply-templates select="ref" mode="#current"> <xsl:with-param name="referenceNode.title" select="$referenceNode.title" as="item()*"/> </xsl:apply-templates> <!--in case there something (like els:log)--> <xsl:apply-templates select="ref/*" mode="#current"/> </li> </xsl:template> <!--only called for generating the referenceNode title, will be wrap into a link--> <xsl:template match="referenceNode/verbalization" mode="xfRes:TEE_tree.default.htmlSimplePreview"> <xsl:choose> <xsl:when test="count(*/*) = 1 and */html:p"> <xsl:apply-templates select="*/html:p/node()" mode="#current"/> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="*/node()" mode="#current"/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="referenceNode/ref" mode="xfRes:TEE_tree.default.htmlSimplePreview"> <xsl:param name="referenceNode.title" required="yes" as="item()*"/> <a href="{$ecm:url.ee.prefix}{@xf:targetResId}" target="_blank"> <xsl:sequence select="$referenceNode.title"/> </a> </xsl:template> <xsl:template match="contentNode" mode="xfRes:TEE_tree.default.htmlSimplePreview"> <li class="contentNode"> <xsl:apply-templates select="@xf:id" mode="#current"/> <xsl:apply-templates mode="#current"/> </li> </xsl:template> <xsl:template match="contentNode/content" mode="xfRes:TEE_tree.default.htmlSimplePreview"> <div class="content"> <xsl:apply-templates mode="#current"/> </div> </xsl:template> <xsl:template match="contentNode/content/*" mode="xfRes:TEE_tree.default.htmlSimplePreview"> <xsl:choose> <xsl:when test="namespace-uri(.) = 'http://www.w3.org/1999/xhtml'"> <xsl:apply-templates select="." mode="xfRes:TEE_text.html.default.htmlSimplePreview"/> </xsl:when> <xsl:otherwise> <xsl:variable name="msg" as="xs:string*"> <xsl:text>ERROR : unable to display contentNode properly at </xsl:text> <xsl:value-of select="els:get-xpath(.)"/> </xsl:variable> <xsl:message><xsl:value-of select="$msg"/></xsl:message> <div class="error" style="background-color:red; color:white; padding:0.5em; font-family: monospace;"> <h3 style="margin-bottom:0"><xsl:value-of select="$msg"/></h3> <div> <xsl:apply-templates select="content/*" mode="els:xml2simpleHtml"/> </div> </div> </xsl:otherwise> </xsl:choose> </xsl:template> <!--+==================================================+ | COMMON | +==================================================+--> <xsl:template match="@xf:id" mode="xfRes:TEE_tree.default.htmlSimplePreview"> <xsl:attribute name="id" select="."/> </xsl:template> <!--Default xf element : continue --> <xsl:template match="xf:*" mode="xfRes:TEE_tree.default.htmlSimplePreview"> <xsl:apply-templates mode="#current"/> </xsl:template> <!--except metadata--> <xsl:template match="metadata" mode="xfRes:TEE_tree.default.htmlSimplePreview"/> <!--Default html element : copy--> <xsl:template match="html:*" mode="xfRes:TEE_tree.default.htmlSimplePreview"> <xsl:copy copy-namespaces="no"> <xsl:copy-of select="@*"/> <xsl:apply-templates mode="#current"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" xmlns="http://www.w3.org/1999/xhtml" exclude-result-prefixes="#all" version="3.0"> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>Convert any XML to HTML div/span based on text occurence</xd:p> </xd:desc> </xd:doc> <!--==================================================--> <!--INIT--> <!--==================================================--> <xsl:template match="/"> <xsl:apply-templates select="." mode="els:xml2simpleHtml"/> </xsl:template> <!--==================================================--> <!--MAIN--> <!--==================================================--> <xsl:template match="*" mode="els:xml2simpleHtml"> <xsl:variable name="element.name" as="xs:string"> <xsl:choose> <xsl:when test="preceding-sibling::text()[normalize-space(.)] or following-sibling::text()[normalize-space(.)]"> <xsl:text>span</xsl:text> </xsl:when> <xsl:otherwise> <xsl:text>div</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:element name="{$element.name}"> <xsl:attribute name="class" select="local-name()"/> <xsl:apply-templates select="@* | node()" mode="#current"/> </xsl:element> </xsl:template> <xsl:template match="@*" mode="els:xml2simpleHtml"> <xsl:attribute name="{concat('data-xml-', local-name(.))}" select="."/> </xsl:template> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" xmlns:xf="http://www.lefebvre-sarrut.eu/ns/xmlfirst" xmlns:xfRes="http://www.lefebvre-sarrut.eu/ns/xmlfirst/ecm/resources" xmlns="http://www.w3.org/1999/xhtml" exclude-result-prefixes="#all" version="3.0"> <xsl:import href="xslLib:/xslLib/xml2simpleHtml.xsl"/> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>Copy html elements and resolve conf</xd:p> <xd:p>Generate the default full html preview for EE of type text whose contentNode are already HTML</xd:p> </xd:desc> </xd:doc> <xsl:output method="xhtml" indent="no"/> <!--+==================================================+ | INIT. | +==================================================+--> <!--No modes for standalone execution--> <xsl:template match="/"> <xsl:apply-templates select="." mode="xfRes:TEE_text.html.default.htmlSimplePreview"/> </xsl:template> <!--Mode xfRes:htmlSimplePreview for using from insertMetaInsideBody.xsl--> <xsl:template match="/" mode="xfRes:htmlSimplePreview"> <xsl:apply-templates select="." mode="xfRes:TEE_text.html.default.htmlSimplePreview"/> </xsl:template> <!--+==================================================+ | MAIN | +==================================================+--> <xsl:template match="/" mode="xfRes:TEE_text.html.default.htmlSimplePreview"> <html> <head> <title><xsl:value-of select="tokenize(base-uri(.), '/')[last()]"/></title> </head> <body> <xsl:apply-templates mode="#current"/> </body> </html> </xsl:template> <xsl:template match="xf:metadata" mode="xfRes:TEE_text.html.default.htmlSimplePreview"/> <xsl:template match="xf:*" mode="xfRes:TEE_text.html.default.htmlSimplePreview"> <xsl:apply-templates mode="#current"/> </xsl:template> <xsl:template match="node() | @*" mode="xfRes:TEE_text.html.default.htmlSimplePreview"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" xmlns:xf="http://www.lefebvre-sarrut.eu/ns/xmlfirst" xmlns:xfRes="http://www.lefebvre-sarrut.eu/ns/xmlfirst/ecm/resources" xmlns:ecm="http://www.lefebvre-sarrut.eu/ns/xmlfirst/ecm" xmlns="http://www.w3.org/1999/xhtml" xpath-default-namespace="http://www.lefebvre-sarrut.eu/ns/xmlfirst" exclude-result-prefixes="#all" version="3.0"> <xsl:import href="xf-common.xsl"/> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>Common functions and templates for XMLfirst ECM Resources HTML previews</xd:p> </xd:desc> </xd:doc> <xsl:param name="xfRes:editorialEntity.code" select="/editorialEntity/@code" as="xs:string"/> <!--only one css allowed (ECM constraint), use css import if you need more--> <xsl:param name="xfRes:css.uri" select="xfRes:getCssRelativeUri($xfRes:editorialEntity.code, $xfRes:baseUri, 'ecm.htmlSimplePreview.style')" as="xs:string?"/> <!--CSS name and path can be overrided (usefull for xspec for example)--> <xsl:param name="xfRes:css.path" as="xs:string?"/> <xsl:param name="xfRes:css.name" as="xs:string?"/> <!--Normalize css path by adding a final "/"--> <xsl:variable name="xfRes:css.path.normalized" select="if(exists($xfRes:css.path) and not(ends-with($xfRes:css.path, '/'))) then(concat($xfRes:css.path, '/')) else($xfRes:css.path)" as="xs:string?"/> <!--Normalize css path from xfRes:css.uri by adding a final "/"--> <xsl:variable name="xfRes:css.uri.path.normalized" select="concat(els:getFolderPath($xfRes:css.uri), '/')" as="xs:string?"/> <!--Get the final CSS uri after overriding--> <xsl:variable name="xfRes:css.final.uri" as="xs:string?"> <xsl:choose> <xsl:when test="exists($xfRes:css.uri)"> <xsl:sequence select="concat( ($xfRes:css.path.normalized, $xfRes:css.uri.path.normalized)[1], ($xfRes:css.name, els:getFileName($xfRes:css.uri))[1] )"/> </xsl:when> <xsl:when test="exists($xfRes:css.path) or exists($xfRes:css.name)"> <xsl:sequence select="concat($xfRes:css.path.normalized, $xfRes:css.name)"/> </xsl:when> </xsl:choose> </xsl:variable> <xsl:template name="xfRes:htmlPreview.makeHtmlHead"> <head> <title><xsl:value-of select="els:getFileName($xfRes:baseUri)"/></title> <xsl:if test="not(empty($xfRes:css.final.uri))"> <link type="text/css" rel="Stylesheet" href="{$xfRes:css.final.uri}"/> </xsl:if> </head> </xsl:template> <xd:doc> <xd:desc> <xd:p>A template to add debuging informations : to be called from any htmlPreview for example</xd:p> </xd:desc> </xd:doc> <xsl:template name="xfRes:htmlPreview.addDebugInfo"> <xsl:if test="$xfRes:displayDebugInformations"> <div class="ecm_debug" style="display:none;"> <p>Generated at <xsl:value-of select="current-dateTime()"/></p> <p>server.url = <xsl:value-of select="$ecm:server.url"/></p> <p>ee.id = <xsl:value-of select="/editorialEntity/@xf:id"/></p> <p><a href="{concat($ecm:ee.url.begin, /editorialEntity/@xf:id)}" target="_blank">XML</a></p> </div> </xsl:if> </xsl:template> <xsl:template match="html:body" mode="xfRes:htmlPreview.normalizeHTML"> <xsl:copy> <xsl:apply-templates select="@*" mode="#current"/> <xsl:call-template name="xfRes:htmlPreview.addDebugInfo"/> <xsl:apply-templates select="node()" mode="#current"/> </xsl:copy> </xsl:template> <xsl:template match="html:head" mode="xfRes:htmlPreview.normalizeHTML"> <xsl:call-template name="xfRes:htmlPreview.makeHtmlHead"/> </xsl:template> <xsl:template match="node() | @*" mode="xfRes:htmlPreview.normalizeHTML"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" xmlns:functx="http://www.functx.com" xmlns:xf="http://www.lefebvre-sarrut.eu/ns/xmlfirst" xmlns:xfRes="http://www.lefebvre-sarrut.eu/ns/xmlfirst/ecm/resources" xmlns:xfResTeeConf="http://www.lefebvre-sarrut.eu/ns/xmlfirst/ecm/resources/TEE-conf" xmlns:ecm="http://www.lefebvre-sarrut.eu/ns/xmlfirst/ecm" xmlns:html="http://www.w3.org/1999/xhtml" xmlns="http://www.lefebvre-sarrut.eu/ns/xmlfirst" xpath-default-namespace="http://www.lefebvre-sarrut.eu/ns/xmlfirst" exclude-result-prefixes="#all" version="3.0"> <xsl:import href="xf-lib:/xf-lib/xsl/_common/xf-common.xsl"/> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>Common functions and templates for XMLfirst ECM Resources</xd:p> </xd:desc> </xd:doc> <!-- Current xsl fileName for els:log--> <xsl:param name="els:currentResName" required="no" select="els:getFileName(static-base-uri())" as="xs:string"/> <xd:doc> <xd:desc> <xd:p>Parameters "ecm:xxx" : catches every parameters sent by the ECM to all XSLT</xd:p> </xd:desc> </xd:doc> <!--PARAM sent by ECM (as string)--> <!--FIXME : delete default value when the param is sent for each env--> <xsl:param name="ecm:server.url" select="''" as="xs:string"/> <!--afficher ou non les métadonnées--> <xsl:param name="ecm:htmlProofing-metadata" select="'false'" as="xs:string"/> <!--ajoute des marges permettant d’annoter le document imprimé--> <xsl:param name="ecm:htmlProofing-margin" select="'false'" as="xs:string"/> <!--afficher ou non les suivis de modifications --> <xsl:param name="ecm:htmlProofing-revisedMode" select="'false'" as="xs:string"/> <!--affichage ou non des métadonnées des liens (disponible uniquement pour la prévisualisation d'une entité de type arbre ou d'un nœud de structure)--> <xsl:param name="ecm:htmlProofing-linkMetadata" select="'false'" as="xs:string"/> <!--affichage ou non du contenu des nœuds d’accrochage (disponible uniquement pour la prévisualisation d'une entité de type arbre ou d'un nœud de structure)--> <xsl:param name="ecm:htmlProofing-contentOfLinks" select="'false'" as="xs:string"/> <xd:doc> <xd:desc> <xd:p>Variables</xd:p> </xd:desc> </xd:doc> <!--ecm:ee.url.begin should be a variable but it might be usefull to override it for XSpec--> <xsl:param name="ecm:ee.url.begin" select="concat($ecm:server.url, 'ecm-core/api/xmlExporter/exportToXML?flashId=')" as="xs:string"/> <!--Most of the time, image are called with a relativ URI, so we don't need to add this. But in the case of proofing, the ECM open a new window with target="_blank" so we need to add it there.--> <xsl:variable name="ecm:img.url.begin" select="concat($ecm:server.url,'ecm-core')" as="xs:string"/> <xsl:variable name="ecm:url.ee.prefix" select="'#/editorialEntity/'" as="xs:string"/> <!--baseUri may be lost in multi-step xslt so we declare a variable to be override and use at the good places--> <xsl:variable name="xfRes:baseUri" select="base-uri(/)" as="xs:anyURI"/> <xsl:variable name="xfRes:xf-ecmRes.main.uri" as="xs:anyURI?"> <xsl:if test="$ecm:server.url = ''"> <!--localy--> <xsl:sequence select="resolve-uri('../../', static-base-uri())"/> </xsl:if> </xsl:variable> <xsl:param name="xfRes:displayDebugInformations" as="xs:boolean"> <xsl:choose> <!--Don't display debug information localy (because Xspec won't work with current-dateTime)--> <xsl:when test="$ecm:server.url = ''"><!--localy--> <xsl:sequence select="false()"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="true()"/> </xsl:otherwise> </xsl:choose> </xsl:param> <!--=========================================================================--> <!--FUNCTIONS--> <!--=========================================================================--> <xsl:function name="xf:getEEdocByFlashId" as="document-node()"> <xsl:param name="id" as="xs:string"/> <xsl:variable name="ee.uri" select="concat($ecm:ee.url.begin, $id)" as="xs:string"/> <xsl:choose> <xsl:when test="doc-available($ee.uri)"> <xsl:sequence select="doc($ee.uri)"/> </xsl:when> <xsl:otherwise> <xsl:document> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="$els:currentResName" as="xs:string"/> <xsl:with-param name="xpathContext" select="''" as="xs:string"/> <xsl:with-param name="level" select="'error'" as="xs:string"/> <xsl:with-param name="code" select="'ECM.EE.UNAVAILABLE'" as="xs:string"/> <xsl:with-param name="description" as="xs:string">EE with id '<xsl:value-of select="$id"/>' is not available at uri: <xsl:value-of select="$ee.uri"/> </xsl:with-param> </xsl:call-template> </xsl:document> </xsl:otherwise> </xsl:choose> </xsl:function> <xsl:function name="xfRes:getTEEconfResource" as="element()*"> <xsl:param name="editorialEntity.code" as="xs:string"/> <xsl:param name="resource.type" as="xs:string"/> <xsl:variable name="TEE-conf.name" select="concat($editorialEntity.code, '.ecm-resources.conf.xml')" as="xs:string"/> <xsl:variable name="TEE-conf.uri" select="resolve-uri($TEE-conf.name, concat($xfRes:xf-ecmRes.main.uri, 'TEE-conf/'))" as="xs:anyURI"/> <xsl:choose> <xsl:when test="doc-available($TEE-conf.uri)"> <xsl:sequence select="doc($TEE-conf.uri)/xfResTeeConf:resources/xfResTeeConf:*[@type = $resource.type]"/> </xsl:when> <xsl:otherwise> <xsl:message>[ERROR] document <xsl:value-of select="$TEE-conf.uri"/> is not available</xsl:message> </xsl:otherwise> </xsl:choose> </xsl:function> <!--This function aimed at beeing execute localy but not server side (ECM will add the css automaticaly from TEE_conf file)--> <xsl:function name="xfRes:getCssRelativeUri" as="xs:string?"> <xsl:param name="editorialEntity.code" as="xs:string"/> <xsl:param name="baseUri" as="xs:anyURI"/> <xsl:param name="resource.css.type" as="xs:string"/> <xsl:choose> <xsl:when test="$ecm:server.url != ''"> <xsl:message>[INFO][xfRes:getCssRelativeUri()] Do not try to get css path when executing this xslt on the ECM server</xsl:message> </xsl:when> <xsl:when test="empty($xfRes:xf-ecmRes.main.uri)"> <xsl:message>[WARNING][xfRes:getCssRelativeUri()] $xfRes:xf-ecmRes.main.uri is empty, do not try to get css path</xsl:message> </xsl:when> <!--If not, try to read the TEE_conf file--> <xsl:otherwise> <xsl:variable name="resource.css" select="xfRes:getTEEconfResource($editorialEntity.code, $resource.css.type)" as="element()*"/> <xsl:variable name="resource.css.jar-href" select="$resource.css/@jar-href" as="xs:string?"/> <xsl:if test="exists($resource.css.jar-href) and starts-with($resource.css.jar-href, 'xf-ecmRes/')"> <xsl:variable name="resource.css.uri" as="xs:string"> <xsl:variable name="resource.css.uri.tmp" as="xs:string*"> <xsl:value-of select="$xfRes:xf-ecmRes.main.uri"/> <xsl:choose> <!--src/main/web-resources will create a folder within the jar--> <xsl:when test="starts-with($resource.css.jar-href, 'xf-ecmRes/web-resources/')"> <xsl:sequence select="substring-after($resource.css.jar-href, 'xf-ecmRes/')"/> </xsl:when> <!--src/main/resources will not create a folder within the jar--> <!--let's consider this case--> <xsl:when test="starts-with($resource.css.jar-href, 'xf-ecmRes/')"> <xsl:sequence select="concat('resources/', substring-after($resource.css.jar-href, 'xf-ecmRes/'))"/> </xsl:when> <xsl:otherwise> <xsl:message>[WARNING] Unable to localte css resource for <xsl:value-of select="$resource.css.jar-href"/></xsl:message> <xsl:sequence select="$resource.css.jar-href"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:sequence select="string-join($resource.css.uri.tmp, '')"/> </xsl:variable> <xsl:sequence select="els:getRelativePath(els:getFolderPath(string($baseUri)), $resource.css.uri)"/> <!--DEBUG--> <!--<xsl:message>els:getFolderPath(string($baseUri))= <xsl:value-of select="els:getFolderPath(string($baseUri))"/></xsl:message>--> <!--<xsl:message>$resource.css.uri= <xsl:value-of select="$resource.css.uri"/></xsl:message>--> </xsl:if> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc> <xd:desc> <xd:p>Group metadata with same code so they become multivalued meta </xd:p> </xd:desc> <xd:param name="metadata">Set of meta</xd:param> <xd:return>Set of meta grouped</xd:return> </xd:doc> <xsl:function name="xfRes:groupMultivaluedMeta" as="element(xf:metadata)"> <xsl:param name="metadata" as="element(xf:metadata)"/> <metadata> <xsl:copy-of select="$metadata/@*"/> <xsl:for-each-group select="$metadata/*" group-by="self::meta/@code"> <meta code="{current-grouping-key()}"> <xsl:for-each select="current-group()/@*"> <xsl:copy-of select="."/> </xsl:for-each> <xsl:sequence select="current-group()/node()"/> </meta> </xsl:for-each-group> </metadata> </xsl:function> <xd:doc> <xd:desc> <xd:p>Removes duplicated values from a (multivalued) meta </xd:p> </xd:desc> <xd:param name="meta">Meta with possibly duplicates values</xd:param> <xd:return>Meta with uniques values</xd:return> </xd:doc> <xsl:function name="xfRes:RemoveDuplicateMetaValues" as="element(xf:meta)"> <xsl:param name="meta" as="element(xf:meta)"/> <xsl:variable name="grouped-values"> <xsl:for-each-group select="$meta/*" group-starting-with="value"> <meta> <xsl:sequence select="current-group()"/> </meta> </xsl:for-each-group> </xsl:variable> <meta> <xsl:sequence select="$meta/@*"/> <xsl:sequence select="functx:distinct-deep($grouped-values/*)/*"/> </meta> </xsl:function> <xd:doc> <xd:desc> <xd:p>Update a meta verbalization element by looking for its current value in the appropriate referential database.</xd:p> <xd:p>FIXME : A implémenter quand le format des référentiels sera défini + ces derniers accessibles depuis une base XML. Pour le moment -> simple copie de la méta en entrée.</xd:p> </xd:desc> <xd:param name="meta">[element(meta)] The meta element whose verbalization needs to be updated. It must contains a ref/@xf:idRef pointing to a referential database entry.</xd:param> <xd:return>[element(meta)] The updated meta element.</xd:return> </xd:doc> <xsl:function name="xfRes:updateMetaVerbalization" as="element(meta)"> <xsl:param name="meta" as="element(meta)"/> <xsl:if test="not($meta/value/ref[@xf:refType = 'xf:referenceItemRef'])"> <xsl:message>[ERROR][xfRes:updateMetaVerbalization] The meta must contain a reference to a referential database entry (ref/@xf:refType = 'xf:referenceItemRef').</xsl:message> </xsl:if> <!-- TO DO --> <xsl:sequence select="$meta"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Simple template to update all metadata verbalizations.</xd:p> </xd:desc> </xd:doc> <xsl:template match="meta[value/ref/@xf:refType = 'xf:referenceItemRef']" mode="xfRes:updateMetaVerbalization"> <xsl:sequence select="xfRes:updateMetaVerbalization(.)"/> </xsl:template> <xd:doc> <xd:desc> <xd:p>Default copy for mode xfRes:updateMetaVerbalization.</xd:p> </xd:desc> </xd:doc> <xsl:template match="node() | @*" mode="xfRes:updateMetaVerbalization"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> <xd:doc> <xd:desc> <xd:p>Returns the short/long label of an identified referential database entry.</xd:p> <xd:p>FIXME : A revoir lorsque les référentiels seront mis en place (la fonction ne doit pas être utilisée pour le moment).</xd:p> </xd:desc> <xd:param name="refXML">[element(xf:referenceTable)] XML serialization of the referential database (FLASH format).</xd:param> <xd:param name="entryId">[xs:string] The database entry ID.</xd:param> <xd:param name="labelType">[xs:string] Possible values: "short" or "long".</xd:param> <xd:return>[xs:string?] The short/long label, if it was found.</xd:return> </xd:doc> <xsl:function name="xfRes:getRefEntryLabel" as="xs:string?"> <xsl:param name="refXML" as="element(xf:referenceTable)"/> <xsl:param name="entryId" as="xs:string"/> <xsl:param name="labelType" as="xs:string"/> <xsl:variable name="authorisedLabelTypes" select="('short','long')" as="xs:string+"/> <xsl:if test="not($labelType = $authorisedLabelTypes)"> <xsl:message>[ERROR][xfRes:getRefEntryLabel] Unknown label type: <xsl:value-of select="$labelType"/>.</xsl:message> </xsl:if> <xsl:value-of select="$refXML//referenceItem[@id = $entryId]/label[@type = $labelType]"/> </xsl:function> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" xmlns:xslLib="http://www.lefebvre-sarrut.eu/ns/els/xslLib" xmlns:xf="http://www.lefebvre-sarrut.eu/ns/xmlfirst" exclude-result-prefixes="#all" version="3.0"> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>Ensemble de variables / fonctions / templates utilitaires permettant de manipuler des données FLASH (toutes maisons).</xd:p> <xd:p>/!\ TODO : L'idée est de ne mettre dans cette XSL que des fonctions / templates pouvant être utilisés pour tous les documents FLASH + de mettre la XSL en commun.</xd:p> </xd:desc> </xd:doc> <!-- IMPORTS --> <xsl:import href="xslLib:/xslLib/els-common.xsl"/> <xsl:import href="xslLib:/xslLib/els-log.xsl"/> <xsl:import href="xslLib:/xslLib/xml2json/xjson2json.xsl"/> <!-- VARIABLES --> <!-- Nom de la XSL, pour els:log appelés directement depuis cette xsl--> <xsl:param name="els:currentResName" required="no" select="els:getFileName(static-base-uri())" as="xs:string"/> <!--dalloz, efl, el...--> <xsl:param name="xf:company" select="'els'" as="xs:string"/> <!-- KEYS --> <!-- Toutes les relations, identifiées par leur ID (cas d'usage : obtenir la relation à partir d'un renvoiAutrui, pour identifier la cible) --> <xsl:key name="xf:getRelationById" match="xf:relation" use="@xf:id"/> <!-- Toutes les EE, identifiées par leur ID --> <xsl:key name="xf:getEEById" match="xf:editorialEntity" use="@xf:id"/> <!--+==================================================+ | FONCTIONS / Informations diverses sur les EE | +==================================================+--> <!--INTERFACE : this function has to be overrided by the calling xslt--> <xsl:function name="xf:getEEdocByFlashId" as="document-node()"> <xsl:param name="id" as="xs:string"/> <xsl:document> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="$els:currentResName" as="xs:string"/> <xsl:with-param name="xpathContext" select="''" as="xs:string"/> <xsl:with-param name="level" select="'error'" as="xs:string"/> <xsl:with-param name="code" select="'function_getEEdocByFlashId-missingImplementation'" as="xs:string"/> <xsl:with-param name="description" as="xs:string">Calling xfPub:getEEdocByFlashId('<xsl:value-of select="$id"/>') : Please override this function in your own XSLT !</xsl:with-param> </xsl:call-template> </xsl:document> </xsl:function> <xd:doc> <xd:desc> <xd:p>Récupère le code TEE de l'EE <xd:ref name="ee" type="parameter">$ee</xd:ref> (attribut @code de /xf:editorialEntity - toute EE).</xd:p> </xd:desc> <xd:param name="ee">[element(xf:editorialEntity)?] Une EE quelconque.</xd:param> <xd:return>[xs:string] La valeur du code TEE, ou une chaîne vide si non-trouvée.</xd:return> </xd:doc> <xsl:function name="xf:getTEE" as="xs:string"> <xsl:param name="ee" as="element(xf:editorialEntity)?"/> <xsl:sequence select="($ee/@code,'')[1]"/> </xsl:function> <!--+==================================================+ | FUNCTIONS / FLASH Relations | +==================================================+--> <xd:doc> <xd:desc> <xd:p>Generate an unique relation id (especially usefull for xspec as replacement of generate-id())-</xd:p> </xd:desc> </xd:doc> <!-- don't use as="xs:ID" which is not compatible with gauloisPipe, use as="xs:string" instead--> <!--FIXME : when used in SAS where multiple EE are allowed, the count could be contextualized to the current EE (but then need to add EE count, so it remains unique in the whole SAS document) : necessary ?--> <xsl:function name="xf:generateRelationId" as="xs:string"> <xsl:param name="e" as="element()"/> <xsl:value-of select="concat('relation-', local-name($e), '-', count($e/preceding::*[local-name(.) = local-name($e)]) + 1)"/> </xsl:function> <!--2 arg signature of xf:makeHistoricalIdAttributeValue--> <xsl:function name="xf:makeHistoricalIdAttributeValue" as="xs:string"> <xsl:param name="e" as="element()?"/> <xsl:param name="historicalId" as="xs:string?"/> <xsl:sequence select="xf:makeHistoricalIdAttributeValue($e, $historicalId, $xf:company)"/> </xsl:function> <!--Flash use its own id (UUID) but its need a mapping to the historical ID, so the persistence of ID remains the same during import/export--> <!--This function makes an AVT (Attribute Value Template) to say Flash to replace it with the mapped hitorical ID--> <xsl:function name="xf:makeHistoricalIdAttributeValue" as="xs:string"> <xsl:param name="e" as="element()?"/> <xsl:param name="historicalId" as="xs:string?"/> <xsl:param name="company" as="xs:string?"/> <xsl:choose> <xsl:when test="empty($historicalId)"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="level" select="'error'"/> <xsl:with-param name="code" select="'xf:makeHistoricalIdAttributeValue_IS-EMPTY'"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="xpathContext" select="$e"/> <xsl:with-param name="description">$historicalId is empty <xsl:if test="not(empty($e))"> at <xsl:value-of select="els:get-xpath($e)"/></xsl:if></xsl:with-param> </xsl:call-template> <xsl:sequence select="''"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="concat('{historicalId:', if(not(($company, 'els')[1] = ('', 'els'))) then(concat($company, '_')) else() , $historicalId , '}')"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc> <xd:desc> </xd:desc> </xd:doc> <xd:doc> <xd:desc> <xd:p>FE-117 : a function to generate a json AVT query from target attributes of a link.</xd:p> <xd:p>When the ID is unknown on might give a "flash query" instead as an AVT (Attribute Value Template)</xd:p> <xd:p>Flash will try to resolve the query (during import, edition or just regularly in the life time of the editorial entity)</xd:p> </xd:desc> <xd:param name="e">The current link (only usefull for logging messages)</xd:param> <xd:param name="metaValuePair"> <xd:p>A sequence of strings for each meta of the query : ('metaName1=value1', 'metaName2=value2', '...')</xd:p> <xd:p>Special values meta:</xd:p> <xd:ul> <xd:li><xd:i>systemTee</xd:i>: code of the target TEE</xd:li> <xd:li><xd:i>fullText</xd:i>: a string for full text search if necessary</xd:li> </xd:ul> <xd:p>Multivaluated meta: add & between values</xd:p> <xd:p>To query a meta of the parent EE (parent by referenceNode) use meta name = parent.codeTR.codeMeta=...</xd:p> <xd:p>To query a meta of a children EE (children by referenceNode) use meta name = child.codeTR.codeMeta=...</xd:p> </xd:param> <xd:return>an JSON string</xd:return> <!--FIXME : to be continued... : - & in a meta value will split it => change this separator ! - param for full text with default value - multivaluated meta ? - Totally change this function, param as xml ?--> </xd:doc> <!----> <xsl:function name="xf:makeQueryIdAttributeValue" as="xs:string"> <xsl:param name="e" as="element()?"/> <xsl:param name="metaValuePair" as="xs:string*"/> <xsl:choose> <xsl:when test="empty($metaValuePair)"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="level" select="'error'"/> <xsl:with-param name="code" select="'xf:makeQueryIdAttributeValue-IS-EMPTY'"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="xpathContext" select="$e"/> <xsl:with-param name="description">$metaValuePair is empty <xsl:if test="not(empty($e))"> at <xsl:value-of select="els:get-xpath($e)"/></xsl:if></xsl:with-param> </xsl:call-template> <xsl:sequence select="''"/> </xsl:when> <xsl:otherwise> <xsl:variable name="query.xjson" as="element(fn:map)"> <fn:map> <xsl:if test="$metaValuePair[normalize-space(substring-before(., '='))='fullText'][normalize-space(substring-after(., '='))!='']"> <fn:string key="fullText"> <xsl:value-of select="normalize-space(substring-after($metaValuePair[normalize-space(substring-before(., '='))='fullText'], '='))"/> </fn:string> </xsl:if> <fn:array key="metadata"> <xsl:for-each select="$metaValuePair[normalize-space(substring-before(., '='))!='fullText'][normalize-space(substring-before(., '='))!=''][normalize-space(substring-after(., '='))!='']"> <xsl:variable name="meta.name" select="substring-before(., '=')" as="xs:string"/> <xsl:variable name="meta.value" select="substring-after(., '=')" as="xs:string"/> <fn:map> <fn:string key="code"><xsl:value-of select="$meta.name"/></fn:string> <fn:array key="values"> <xsl:for-each select="tokenize($meta.value, '&')[normalize-space(.)!='']"> <fn:string><xsl:value-of select="."/></fn:string> </xsl:for-each> </fn:array> </fn:map> </xsl:for-each> </fn:array> </fn:map> </xsl:variable> <xsl:value-of select="concat('{query:', xslLib:xjson2json($query.xjson), '}')"/> </xsl:otherwise> </xsl:choose> </xsl:function> <!--+==================================================+ | FONCTIONS / Manipulation de métadonnées FLASH | +==================================================+--> <xd:doc> <xd:desc> <xd:p>Détermine, selon <xd:ref name="condition" type="parameter">$condition</xd:ref>, si un élément donné (<xd:ref name="e" type="parameter">$e</xd:ref>) possède :</xd:p> <xd:ul> <xd:li>au moins une métadonnée dont le code correspond à une des valeurs de <xd:ref name="codes" type="parameter">$codes</xd:ref> (<xd:ref name="condition" type="parameter">$condition</xd:ref> = 'any').</xd:li> <xd:li>ou une métadonnée pour chaque valeur de <xd:ref name="codes" type="parameter">$codes</xd:ref> (<xd:ref name="condition" type="parameter">$condition</xd:ref> = 'all').</xd:li> </xd:ul> <xd:p>Si l'élément ne peut pas posséder de métadonnées selon le schéma FLASH (bloc <xf:metadata>), renvoie systématiquement false().</xd:p> </xd:desc> <xd:param name="e">[element()] Elément (<xf:*>) à partir duquel les métadonnées seront interrogées.</xd:param> <xd:param name="codes">[xs:string+] Code(s) de la/des métadonnée(s) à tester.</xd:param> <xd:param name="condition">[xs:string] Condition du test (valeurs 'any' ou 'all').</xd:param> <xd:return>[xs:boolean?] Le résultat du test.</xd:return> </xd:doc> <xsl:function name="xf:hasMeta" as="xs:boolean?"> <xsl:param name="e" as="element()"/> <xsl:param name="codes" as="xs:string+"/> <xsl:param name="condition" as="xs:string"/> <xsl:choose> <xsl:when test="not($condition = ('any','all'))"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="$els:currentResName"/> <xsl:with-param name="level" select="'error'"/> <xsl:with-param name="code" select="'FUNCTION_paramKO'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="xpathContext" select="$e"/> <xsl:with-param name="description">[xf:hasMeta] La valeur '<xsl:value-of select="$condition"/>' n'est pas autorisée pour le paramètre $condition.</xsl:with-param> </xsl:call-template> </xsl:when> <xsl:when test="not($e/self::xf:editorialEntity or $e/self::xf:structuralNode or $e/self::xf:referenceNode or $e/self::xf:queryNode or $e/self::xf:contentNode or $e/self::xf:relation or $e/self::xf:referenceItem)"> <xsl:sequence select="false()"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="if ($condition = 'any') then ($e/xf:metadata/xf:meta/@code = $codes) else (every $code in $codes satisfies xf:hasMeta($e,$code,'any'))"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc> <xd:desc> <xd:p>Signature à 2 arguments de la fonction xf:hasMeta($e as element(), $codes as xs:string+, $condition as xs:string).</xd:p> <xd:p>Détermine si un élément donné (<xd:ref name="e" type="parameter">$e</xd:ref>) possède au moins une métadonnée dont le code correspond à une des valeurs de <xd:ref name="codes" type="parameter">$codes</xd:ref> ($condition = 'any').</xd:p> <xd:p>Si l'élément ne peut pas posséder de métadonnées selon le schéma FLASH (bloc <xf:metadata>), renvoie systématiquement false().</xd:p> </xd:desc> <xd:param name="e">[element()] Elément (<xf:*>) à partir duquel les métadonnées seront interrogées.</xd:param> <xd:param name="codes">[xs:string+] Code(s) de la/des métadonnée(s) à tester.</xd:param> <xd:return>[xs:boolean?] Le résultat du test.</xd:return> </xd:doc> <xsl:function name="xf:hasMeta" as="xs:boolean?"> <xsl:param name="e" as="element()"/> <xsl:param name="codes" as="xs:string+"/> <xsl:sequence select="xf:hasMeta($e,$codes,'any')"/> </xsl:function> <xd:doc> <xd:desc>Indique si une métadonnée est de type HTML, à partir de la valeur de son attribut @as.</xd:desc> <xd:param name="meta">[element(xf:meta)?] La métadonnée à tester.</xd:param> <xd:return>[xs:boolean] Le résultat du test indiquant si la métadonnée est de type HTML.</xd:return> </xd:doc> <xsl:function name="xf:isHTMLMeta" as="xs:boolean"> <xsl:param name="meta" as="element(xf:meta)?"/> <xsl:sequence select="matches($meta/@as,'^element\(html:')"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Signature à 2 arguments de la fonction xf:getMeta($e as element(), $metaCode as xs:string, $verbose as xs:boolean).</xd:p> <xd:p>Retourne la métadonnée (<xf:meta>) présente sous l'élément <xd:ref name="e" type="parameter">$e</xd:ref> et dont le code est <xd:ref name="metaCode" type="parameter">$metaCode</xd:ref>.</xd:p> <xd:p>En fonction de <xd:ref name="e" type="parameter">$e</xd:ref>, renvoie aussi bien une métadonnée d'editorialEntity, de referenceNode, de relation, etc.</xd:p> <xd:p>Par défaut, les messages d'erreur en cas de métadonnée introuvable par exemple sont désactivés.</xd:p> </xd:desc> <xd:param name="e">[element()] Elément (<xf:*>) à partir duquel les métadonnées seront interrogées.</xd:param> <xd:param name="metaCode">[xs:string] Code de la métadonnée (attribut @code de <xf:meta>).</xd:param> <xd:return>[element(xf:meta)*] La métadonnée identifiée, ou les métadonnées (si plusieurs occurrences pour un même code).</xd:return> </xd:doc> <xsl:function name="xf:getMeta" as="element(xf:meta)*"> <xsl:param name="e" as="element()"/> <xsl:param name="metaCode" as="xs:string"/> <xsl:sequence select="xf:getMeta($e,$metaCode,false())"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne la métadonnée (<xf:meta>) présente sous l'élément <xd:ref name="e" type="parameter">$e</xd:ref> et dont le code est <xd:ref name="metaCode" type="parameter">$metaCode</xd:ref>.</xd:p> <xd:p>En fonction de <xd:ref name="e" type="parameter">$e</xd:ref>, renvoie aussi bien une métadonnée d'editorialEntity, de referenceNode, de relation, etc.</xd:p> <xd:p>/!\ C'est une erreur dans les données entrantes d'avoir plusieurs occurrences d'une métadonnée avec le même code, mais en cours de traitement il peut arriver qu'on "duplique" une métadonnée (même code, sous un même élément).</xd:p> <xd:p>/!\ Une alerte est levée si <xd:ref name="verbose" type="parameter">$verbose</xd:ref> et que plusieurs métadonnées sont trouvées (ou aucune) ; si c'est un comportement voulu, on peut désactiver <xd:ref name="verbose" type="parameter">$verbose</xd:ref> lors de l'appel de la fonction.</xd:p> </xd:desc> <xd:param name="e">[element()] Elément (<xf:*>) à partir duquel les métadonnées seront interrogées.</xd:param> <xd:param name="metaCode">[xs:string] Code de la métadonnée (attribut @code de <xf:meta>).</xd:param> <xd:param name="verbose">[xs:boolean] Génère ou non des messages d'erreur.</xd:param> <xd:return>[element(xf:meta)*] La métadonnée identifiée, ou les métadonnées (si plusieurs occurrences pour un même code).</xd:return> </xd:doc> <xsl:function name="xf:getMeta" as="element(xf:meta)*"> <xsl:param name="e" as="element()"/> <xsl:param name="metaCode" as="xs:string"/> <xsl:param name="verbose" as="xs:boolean"/> <xsl:variable name="meta" select="$e/xf:metadata/xf:meta[@code = $metaCode]" as="element(xf:meta)*"/> <xsl:choose> <xsl:when test="not($e/self::xf:editorialEntity or $e/self::xf:structuralNode or $e/self::xf:referenceNode or $e/self::xf:queryNode or $e/self::xf:contentNode or $e/self::xf:relation or $e/self::xf:referenceItem)"> <xsl:if test="$verbose = true()"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="$els:currentResName"/> <xsl:with-param name="level" select="'error'"/> <xsl:with-param name="code" select="'FUNCTION_paramKO'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="xpathContext" select="$e"/> <xsl:with-param name="description">[xf:getMeta] Les métadonnées ne sont pas autorisées sous l'élément : <xsl:value-of select="name($e)"/>.</xsl:with-param> </xsl:call-template> </xsl:if> <!-- Ne renvoie rien --> </xsl:when> <xsl:when test="count($meta) = 0"> <xsl:if test="$verbose = true()"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="$els:currentResName"/> <xsl:with-param name="level" select="'warning'"/> <xsl:with-param name="code" select="'META_notFound'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="xpathContext" select="$e"/> <xsl:with-param name="description">[xf:getMeta] Aucune métadonnée trouvée avec pour code : <xsl:value-of select="$metaCode"/>.</xsl:with-param> </xsl:call-template> <!-- Ne renvoie rien --> </xsl:if> </xsl:when> <xsl:when test="count($meta) gt 1"> <xsl:if test="$verbose = true()"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="$els:currentResName"/> <xsl:with-param name="level" select="'warning'"/> <xsl:with-param name="code" select="'META_multiple'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="xpathContext" select="$e"/> <xsl:with-param name="description">[xf:getMeta] <xsl:value-of select="count($meta)"/> métadonnées trouvées avec pour code : <xsl:value-of select="$metaCode"/>.</xsl:with-param> </xsl:call-template> </xsl:if> <!-- /!\ Renvoie plusieurs métadonnées --> <xsl:sequence select="$meta"/> </xsl:when> <xsl:otherwise> <!-- Renvoie une seule métadonnée --> <xsl:sequence select="$meta"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne la valeur booléenne (xf:meta[@as = 'xs:boolean']/xf:value) d'une métadonnée.</xd:p> <xd:p>Alerte si plusieurs xf:value booléennes sont détectées.</xd:p> </xd:desc> <xd:param name="meta">[element(xf:meta)] La métadonnée dont la valeur booléenne doit être renvoyée.</xd:param> <xd:return>[xs:boolean?] La valeur booléenne de la métadonnée.</xd:return> </xd:doc> <xsl:function name="xf:getMetaBooleanValue" as="xs:boolean?"> <xsl:param name="meta" as="element(xf:meta)?"/> <xsl:if test="$meta/xf:value[@as = 'xs:boolean'][2]"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="$els:currentResName"/> <xsl:with-param name="level" select="'error'"/> <xsl:with-param name="code" select="'FUNCTION_paramKO'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="xpathContext" select="$meta"/> <xsl:with-param name="description">[xf:getMetaBooleanValue] Plusieurs valeurs booléennes ont été détectées pour la métadonnée : '<xsl:value-of select="$meta/@code"/>'.</xsl:with-param> </xsl:call-template> </xsl:if> <!-- TODO : Mettre une alerte supplémentaire si $meta est empty ? --> <xsl:if test="not(empty($meta))"> <xsl:sequence select="$meta/xf:value[@as = 'xs:boolean'][1] cast as xs:boolean"/> </xsl:if> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne la valeur castée en xs:dateTime (xf:meta/xf:value[@as = 'xs:dateTime']) d'une métadonnée.</xd:p> <xd:p>Alerte si plusieurs xf:value[@as = 'xs:dateTime'] sont détectées, ou si la valeur n'est pas une instance valide de xs:dateTime.</xd:p> </xd:desc> <xd:param name="meta">[element(xf:meta)] La métadonnée dont la valeur castée en xs:dateTime doit être renvoyée.</xd:param> <xd:return>[xs:boolean?] La valeur castée en xs:dateTime de la métadonnée.</xd:return> </xd:doc> <xsl:function name="xf:getMetaDateTimeValue" as="xs:dateTime?"> <xsl:param name="meta" as="element(xf:meta)?"/> <xsl:if test="$meta/xf:value[@as = 'xs:dateTime'][2]"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="$els:currentResName"/> <xsl:with-param name="level" select="'error'"/> <xsl:with-param name="code" select="'FUNCTION_paramKO'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="xpathContext" select="$meta"/> <xsl:with-param name="description">[xf:getMetaDateTimeValue] Plusieurs valeurs xs:dateTime ont été détectées pour la métadonnée : '<xsl:value-of select="$meta/@code"/>'.</xsl:with-param> </xsl:call-template> </xsl:if> <!-- TODO : Mettre une alerte supplémentaire si $meta est empty ? --> <xsl:if test="not(empty($meta))"> <!-- Tentative de casting de la méta en xs:dateTime, erreur + empty-sequence si impossible --> <xsl:choose> <xsl:when test="$meta/xf:value[@as = 'xs:dateTime'][1] castable as xs:dateTime"> <xsl:sequence select="$meta/xf:value[@as = 'xs:dateTime'][1] cast as xs:dateTime"/> </xsl:when> <xsl:otherwise> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="$els:currentResName"/> <xsl:with-param name="level" select="'error'"/> <xsl:with-param name="code" select="'FUNCTION_paramKO'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="xpathContext" select="$meta"/> <xsl:with-param name="description">[xf:getMetaDateTimeValue] La valeur de la métadonnée '<xsl:value-of select="$meta/@code"/>' n'est pas une instance valide de xs:dateTime.</xsl:with-param> </xsl:call-template> <!-- Ne retourne rien --> </xsl:otherwise> </xsl:choose> </xsl:if> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne la/les "valeur(s) textuelle(s)" d'une métadonnée (cf. xf:meta/xf:value).</xd:p> <xd:p>Renvoie un ou plusieurs xs:string* (après normalize-space()) correspondant à tous les enfants <xf:value>.</xd:p> </xd:desc> <xd:param name="meta">[element(xf:meta)] La métadonnée dont la "valeur textuelle" doit être calculée.</xd:param> <xd:return>[xs:string*] Un ou plusieurs xs:string (si la métadonnée est multivaluée).</xd:return> </xd:doc> <xsl:function name="xf:getMetaValue" as="xs:string*"> <xsl:param name="meta" as="element(xf:meta)?"/> <xsl:sequence select="xf:getMetaContent($meta,'value')/normalize-space(.)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne le contenu des enfants <xf:value> d'une métadonnée :</xd:p> <xd:ul> <xd:li>si le contenu est une data simple (ex. : xs:string), renvoie celui-ci après normalize-space() ;</xd:li> <xd:li>si le contenu est de type xf:* ou element(), renvoie les éléments enfants ;</xd:li> <xd:li>sinon, renvoi le contenu inchangé.</xd:li> </xd:ul> <xd:p>Se base sur la présence d'un attribut @as sur xf:value, ou déduit le traitement à appliquer du contenu.</xd:p> <xd:p>Fait appel à la fonction xf:normalizeContentInMeta($elt as element()*).</xd:p> </xd:desc> <xd:param name="meta">[element(xf:meta)] La métadonnée dont le contenu des xf:value doit être restitué.</xd:param> <xd:return>[item()*] Le contenu des xf:value de la métadonnée.</xd:return> </xd:doc> <xsl:function name="xf:getMetaValueContent" as="item()*"> <xsl:param name="meta" as="element(xf:meta)?"/> <!-- Récupération du (ou des) enfant(s) xf:value de la métadonnée --> <xsl:variable name="value" select="xf:getMetaContent($meta,'value')" as="element(xf:value)*"/> <!-- Normalisation des valeurs textuelles, contenu brut sinon --> <xsl:sequence select="xf:normalizeContentInMeta($value)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne la/les "valeur(s) textuelle(s)" de la verbalisation d'une métadonnée référentielle (cf. xf:meta/xf:verbalization).</xd:p> <xd:p>Renvoie un ou plusieurs xs:string* (après normalize-space()) correspondant à tous les enfants <xf:verbalization>.</xd:p> </xd:desc> <xd:param name="meta">[element(xf:meta)] La métadonnée référentielle dont la "valeur textuelle" de la verbalisation doit être calculée.</xd:param> <xd:return>[xs:string*] Un ou plusieurs xs:string (si la métadonnée est multivaluée).</xd:return> </xd:doc> <xsl:function name="xf:getMetaVerbalization" as="xs:string*"> <xsl:param name="meta" as="element(xf:meta)?"/> <xsl:sequence select="xf:getMetaContent($meta,'verbalization')/normalize-space(.)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne le/les ID(s) pointant vers une relation (xf:meta/xf:value/xf:ref[@xf:refType = 'xf:relationRef']/@xf:idRef) d'une métadonnée.</xd:p> <xd:p>Renvoie un ou plusieurs xs:string* (après normalize-space()) correspondant à toutes les valeurs des attributs xf:value/xf:ref/@xf:idRef.</xd:p> </xd:desc> <xd:param name="meta">[element(xf:meta)] La métadonnée dont l'ID de relation doit être calculé.</xd:param> <xd:return>[xs:string*] Un ou plusieurs xs:string (si la métadonnée est multivaluée).</xd:return> </xd:doc> <xsl:function name="xf:getMetaRelationRef" as="xs:string*"> <xsl:param name="meta" as="element(xf:meta)?"/> <xsl:sequence select="xf:getMetaContent($meta,'relationRef')/@xf:idRef"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne le/les ID(s) de référentiel(s) (xf:meta/xf:value/xf:ref[@xf:refType = 'xf:referenceItemRef']/@idRef) d'une métadonnée.</xd:p> <xd:p>Renvoie un ou plusieurs xs:string* (après normalize-space()) correspondant à toutes les valeurs des attributs xf:value/xf:ref/@idRef.</xd:p> </xd:desc> <xd:param name="meta">[element(xf:meta)] La métadonnée dont l'ID de référentiel doit être calculé.</xd:param> <xd:return>[xs:string*] Un ou plusieurs xs:string (si la métadonnée est multivaluée).</xd:return> </xd:doc> <xsl:function name="xf:getMetaReferenceItemRef" as="xs:string*"> <xsl:param name="meta" as="element(xf:meta)?"/> <xsl:sequence select="xf:getMetaContent($meta,'referenceItemRef')/@idRef"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne un contenu de métadonnée. En fonction de <xd:ref name="type" type="parameter">$type</xd:ref>, récupère :</xd:p> <xd:ul> <xd:li>tous les enfants xf:value ;</xd:li> <xd:li>tous les enfants xf:verbalization ;</xd:li> <xd:li>tous les enfants xf:value/xf:ref (entrées de référentiels, relations, etc.).</xd:li> </xd:ul> <xd:p>Renvoie un ou plusieurs item()*.</xd:p> </xd:desc> <xd:param name="meta">[element(xf:meta)] La métadonnée dont le contenu doit être calculé.</xd:param> <xd:param name="type">[xs:string] Le type de contenu à récupérer.</xd:param> <xd:return>[item()*] Le contenu de la métadonnée (plusieurs item() si celle-ci est multivaluée).</xd:return> </xd:doc> <xsl:function name="xf:getMetaContent" as="item()*"> <xsl:param name="meta" as="element(xf:meta)?"/> <xsl:param name="type" as="xs:string"/> <xsl:variable name="tmp.sequence" as="item()*"> <!-- Possibilité d'adapter la manière de récupérer le contenu en fonction de $type --> <xsl:choose> <xsl:when test="$type = 'value'"> <xsl:sequence select="$meta/xf:value"/> </xsl:when> <xsl:when test="$type = 'verbalization'"> <!-- TODO : Est-ce que cela a réellement une utilité ? --> <xsl:sequence select="$meta/xf:verbalization"/> </xsl:when> <xsl:when test="$type = 'referenceItemRef'"> <xsl:sequence select="$meta/xf:value/xf:ref[@xf:refType = 'xf:referenceItemRef']"/> </xsl:when> <xsl:when test="$type = 'relationRef'"> <!-- TODO : La valeur 'xf:relation' est erronée - à corriger dans SAS + ECM --> <xsl:sequence select="$meta/xf:value/xf:ref[@xf:refType = ('xf:relationRef','xf:relation')]"/> </xsl:when> <xsl:otherwise> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="$els:currentResName"/> <xsl:with-param name="level" select="'error'"/> <xsl:with-param name="code" select="'FUNCTION_paramKO'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="xpathContext" select="$meta"/> <xsl:with-param name="description">[xf:getMetaContent] Valeur inconnue pour le paramètre $type : <xsl:value-of select="$type"/>.</xsl:with-param> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:if test="count($tmp.sequence) > 1"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="$els:currentResName"/> <xsl:with-param name="level" select="'debug'"/> <xsl:with-param name="code" select="'FUNCTION_genericMessage'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="xpathContext" select="$meta"/> <xsl:with-param name="description">[xf:getMetaContent] La métadonnée '<xsl:value-of select="$meta/@code"/>' est multivaluée.</xsl:with-param> </xsl:call-template> </xsl:if> <xsl:sequence select="$tmp.sequence"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne un / plusieurs éléments xf:value d'une métadonnée donnée (<xd:ref name="meta" type="parameter">$meta</xd:ref>), s'ils possèdent un enfant xf:field dont le nom est <xd:ref name="fieldName" type="parameter">$fieldName</xd:ref> et la valeur est <xd:ref name="fieldValue" type="parameter">$fieldValue</xd:ref>.</xd:p> </xd:desc> <xd:param name="meta">[element(xf:meta)?] Une métadonnée.</xd:param> <xd:param name="fieldName">[xs:string] Le nom du champ (xf:field/@name) souhaité.</xd:param> <xd:param name="fieldValue">[xs:string] La valeur attendue pour le champ (contenu textuel de xf:field).</xd:param> <xd:return>[element(xf:value)*] Le ou les éléments xf:value qui contiennent le champ recherché.</xd:return> </xd:doc> <xsl:function name="xf:getMetaContentFromField" as="element(xf:value)*"> <xsl:param name="meta" as="element(xf:meta)?"/> <xsl:param name="fieldName" as="xs:string"/> <xsl:param name="fieldValue" as="xs:string"/> <xsl:sequence select="xf:getMetaContent($meta,'value')[matches(@as,'^xf:field')][xf:hasField(.,$fieldName,$fieldValue)]"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne un / plusieurs éléments xf:value d'une métadonnée donnée (<xd:ref name="meta" type="parameter">$meta</xd:ref>), s'ils possèdent un enfant xf:field dont le nom est <xd:ref name="fieldName" type="parameter">$fieldName</xd:ref>.</xd:p> </xd:desc> <xd:param name="meta">[element(xf:meta)?] Une métadonnée.</xd:param> <xd:param name="fieldName">[xs:string] Le nom du champ (xf:field/@name) souhaité.</xd:param> <xd:return>[element(xf:value)*] Le ou les éléments xf:value qui contiennent le champ recherché.</xd:return> </xd:doc> <xsl:function name="xf:getMetaContentFromField" as="element(xf:value)*"> <xsl:param name="meta" as="element(xf:meta)?"/> <xsl:param name="fieldName" as="xs:string"/> <xsl:sequence select="xf:getMetaContent($meta,'value')[matches(@as,'^xf:field')][xf:hasField(.,$fieldName)]"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne l'élément xf:field d'un xf:value donné, dont l'attribut @name correspond à la valeur de <xd:ref name="fieldName" type="parameter">$fieldName</xd:ref>.</xd:p> </xd:desc> <xd:param name="elt">[element(xf:value)?] Un élément xf:value (enfant de xf:meta, typiquement).</xd:param> <xd:param name="fieldName">[xs:string] Le nom du champ (xf:field/@name).</xd:param> <xd:return>[element(xf:field)] L'enfant xf:field correspondant.</xd:return> </xd:doc> <xsl:function name="xf:getField" as="element(xf:field)?"> <xsl:param name="elt" as="element(xf:value)?"/> <xsl:param name="fieldName" as="xs:string"/> <xsl:variable name="field" select="$elt/xf:field[@name = $fieldName]" as="element(xf:field)*"/> <!-- Erreur si plusieurs xf:field identifiés --> <xsl:if test="count($field) > 1"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="$els:currentResName"/> <xsl:with-param name="level" select="'error'"/> <xsl:with-param name="code" select="'mutipleFieldsFound'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="xpathContext" select="$elt"/> <xsl:with-param name="description">[xf:getField] Plusieurs éléments xf:field ont été trouvés avec pour nom : "<xsl:value-of select="$fieldName"/>" ; seul le 1er sera retourné.</xsl:with-param> </xsl:call-template> </xsl:if> <xsl:sequence select="$field[1]"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne le contenu de l'élément xf:field d'un xf:value donné, dont l'attribut @name correspond à la valeur de <xd:ref name="fieldName" type="parameter">$fieldName</xd:ref>.</xd:p> </xd:desc> <xd:param name="elt">[element(xf:value)?] Un élément xf:value (enfant de xf:meta, typiquement).</xd:param> <xd:param name="fieldName">[xs:string] Le nom du champ (xf:field/@name).</xd:param> <xd:return>[item()*] Le contenu (noeud HTML, data, etc.) de l'enfant xf:field correspondant.</xd:return> </xd:doc> <xsl:function name="xf:getFieldContent" as="item()*"> <xsl:param name="elt" as="element(xf:value)?"/> <xsl:param name="fieldName" as="xs:string"/> <!-- Obtient l'élément xf:field et retourne son contenu normalisé /!\ Peut être un élément HTML ou du data --> <xsl:sequence select="xf:getField($elt,$fieldName)/xf:normalizeContentInMeta(.)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Détermine si un élément xf:value donné possède un enfant xf:field dont l'attribut @name correspond à la valeur de <xd:ref name="fieldName" type="parameter">$fieldName</xd:ref>.</xd:p> </xd:desc> <xd:param name="elt">[element(xf:value)?] Un élément xf:value (enfant de xf:meta, typiquement).</xd:param> <xd:param name="fieldName">[xs:string] Le nom du champ (xf:field/@name).</xd:param> <xd:return>[xs:boolean] Le résultat du test déterminant la présence de l'enfant xf:field.</xd:return> </xd:doc> <xsl:function name="xf:hasField" as="xs:boolean"> <xsl:param name="elt" as="element(xf:value)?"/> <xsl:param name="fieldName" as="xs:string"/> <xsl:sequence select="$elt/xf:field/@name = $fieldName"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Détermine si un élément xf:value donné possède un enfant xf:field dont le nom est <xd:ref name="fieldName" type="parameter">$fieldName</xd:ref> et la valeur est <xd:ref name="fieldValue" type="parameter">$fieldValue</xd:ref>.</xd:p> </xd:desc> <xd:param name="elt">[element(xf:value)?] Un élément xf:value (enfant de xf:meta, typiquement).</xd:param> <xd:param name="fieldName">[xs:string] Le nom du champ (xf:field/@name).</xd:param> <xd:param name="fieldValue">[xs:string] La valeur attendue pour le champ (contenu textuel de xf:field).</xd:param> <xd:return>[xs:boolean] Le résultat du test déterminant la présence de l'enfant xf:field.</xd:return> </xd:doc> <xsl:function name="xf:hasField" as="xs:boolean"> <xsl:param name="elt" as="element(xf:value)?"/> <xsl:param name="fieldName" as="xs:string"/> <xsl:param name="fieldValue" as="xs:string"/> <xsl:sequence select="$elt/xf:field[@name = $fieldName] = $fieldValue"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne le contenu d'un ou plusieurs éléments <xf:value> / <xf:field> d'une métadonnée normalisé, selon les règles :</xd:p> <xd:ul> <xd:li>si le contenu est une data simple (ex. : xs:string), renvoie celui-ci après normalize-space() ;</xd:li> <xd:li>si le contenu est de type xf:* ou element(), renvoie les éléments enfants ;</xd:li> <xd:li>sinon, renvoi le contenu inchangé.</xd:li> </xd:ul> <xd:p>Se base sur la présence d'un attribut @as sur xf:value, ou déduit le traitement à appliquer du contenu.</xd:p> </xd:desc> <xd:param name="elt">[element()*] Le(s) élément(s) <xf:value> / <xf:field> dont le contenu doit être retourné normalisé.</xd:param> <xd:return>[item()*] Le contenu normalisé.</xd:return> </xd:doc> <xsl:function name="xf:normalizeContentInMeta" as="item()*"> <xsl:param name="elt" as="element()*"/> <!-- xf:value ou xf:field --> <xsl:for-each select="$elt"> <xsl:variable name="as" select="@as" as="xs:string?"/> <xsl:choose> <!-- Traitement de normalisation induit par @as --> <xsl:when test="$as"> <xsl:sequence select="if (matches($as,'^xs:')) then (normalize-space(.)) else if (matches($as,'^(xf:|element\()')) then (./*) else (.)"/> </xsl:when> <!-- Traitement de normalisation déduit du contenu --> <xsl:otherwise> <xsl:sequence select="if (.[*]) then (./*) else (normalize-space(.))"/> </xsl:otherwise> </xsl:choose> </xsl:for-each> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne la verbalisation (xf:verbalization) associée à un élément xf:ref donné (<xd:ref name="ref" type="parameter">$ref</xd:ref>).</xd:p> <xd:p>/!\ Retourne aussi bien une verbalisation liées à un xf:ref dans une métadonnée ou dans un xf:referenceNode.</xd:p> </xd:desc> <xd:param name="ref">[element(xf:ref)] L'élément xf:ref dont la verbalisation doit être retrounée.</xd:param> <xd:return>[element(xf:verbalization)?] L'élément de verbalisation associé au xf:ref (s'il existe).</xd:return> </xd:doc> <xsl:function name="xf:getRefVerbalization" as="element(xf:verbalization)?"> <xsl:param name="ref" as="element(xf:ref)?"/> <xsl:sequence select="($ref/parent::xf:value/following-sibling::*[1][self::xf:verbalization], $ref[parent::xf:referenceNode]/following-sibling::*[1][self::xf:verbalization])[1]"/> </xsl:function> <!--+==================================================+ | FONCTIONS / Manipulation de référentiels FLASH | +==================================================+--> <xd:doc> <xd:desc> <xd:p>Retourne une entrée de référentiel.</xd:p> <xd:p>Interroge le référentiel FLASH <xd:ref name="refXML" type="parameter">$refXML</xd:ref> et retourne l'entrée dont l'ID est <xd:ref name="entryId" type="parameter">$entryId</xd:ref>.</xd:p> </xd:desc> <xd:param name="refXML">[element(xf:referenceTable)] Le référentiel XML (format FLASH).</xd:param> <xd:param name="entryId">[xs:string] L'ID de l'entrée de référentiel.</xd:param> <xd:return>[element(xf:referenceItem)?] L'entrée de référentiel, si elle a été trouvée.</xd:return> </xd:doc> <xsl:function name="xf:getRefEntry" as="element(xf:referenceItem)?"> <xsl:param name="refXML" as="element(xf:referenceTable)"/> <xsl:param name="entryId" as="xs:string"/> <!-- Obtention de l'entrée de référentiel --> <!-- TODO : A améliorer ? Utilisation de @archived, alerte si l'entrée n'est pas trouvée, etc. --> <xsl:sequence select="$refXML//xf:referenceItem[@id = $entryId]"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne une métadonnée liée à une entrée de référentiel.</xd:p> <xd:p>Retourne la métadonnée dont le code est <xd:ref name="code" type="parameter">$code</xd:ref> pour l'entrée <xd:ref name="refEntry" type="parameter">$refEntry</xd:ref>.</xd:p> </xd:desc> <xd:param name="refEntry">[element(xf:referenceItem)?] Une entrée de référentiel (format FLASH).</xd:param> <xd:param name="code">[xs:string] Le code de la métadonnée à retourner (exemples : "libelleComplet", "libelleAbrege", "CXML_Id", etc.).</xd:param> <xd:return>[element(xf:meta)?] La métadonnée, si elle a été trouvée.</xd:return> </xd:doc> <xsl:function name="xf:getRefEntryMeta" as="element(xf:meta)?"> <xsl:param name="refEntry" as="element(xf:referenceItem)?"/> <xsl:param name="code" as="xs:string"/> <xsl:if test="$refEntry"> <!-- Obtention de la métadonnée correspondant à $code (si elle existe) --> <xsl:sequence select="xf:getMeta($refEntry,$code)"/> </xsl:if> </xsl:function> <xd:doc> <xd:desc> <xd:p>Signature à 3 arguments de la fonction xf:getRefEntryMeta($refEntry as element(xf:referenceItem), $code as xs:string)</xd:p> <xd:p>Retourne une métadonnée liée à une entrée de référentiel.</xd:p> <xd:p>Interroge le référentiel FLASH <xd:ref name="refXML" type="parameter">$refXML</xd:ref> et retourne la métadonnée dont le code est <xd:ref name="code" type="parameter">$code</xd:ref> pour l'entrée <xd:ref name="entryId" type="parameter">$entryId</xd:ref>.</xd:p> </xd:desc> <xd:param name="refXML">[element(xf:referenceTable)] Le référentiel XML (format FLASH).</xd:param> <xd:param name="entryId">[xs:string] L'ID de l'entrée de référentiel.</xd:param> <xd:param name="code">[xs:string] Le code de la métadonnée à retourner (exemples : "libelleComplet", "libelleAbrege", "CXML_Id", etc.).</xd:param> <xd:return>[element(xf:meta)?] La métadonnée, si elle a été trouvée.</xd:return> </xd:doc> <xsl:function name="xf:getRefEntryMeta" as="element(xf:meta)?"> <xsl:param name="refXML" as="element(xf:referenceTable)"/> <xsl:param name="entryId" as="xs:string"/> <xsl:param name="code" as="xs:string"/> <!-- Obtention de l'entrée de référentiel --> <xsl:variable name="referenceItem" select="xf:getRefEntry($refXML,$entryId)" as="element(xf:referenceItem)?"/> <!-- Obtention de la métadonnée correspondant à $code (si elle existe) --> <xsl:sequence select="xf:getRefEntryMeta($referenceItem,$code)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne le contenu d'une métadonnée liée à une entrée de référentiel.</xd:p> <xd:p>Retourne le contenu de la métadonnée dont le code est <xd:ref name="code" type="parameter">$code</xd:ref> pour l'entrée <xd:ref name="refEntry" type="parameter">$refEntry</xd:ref>.</xd:p> <xd:p>Fait appel à la fonction xf:getMetaContent($meta as element(xf:meta?), $type as xs:string) as item()*.</xd:p> </xd:desc> <xd:param name="refEntry">[element(xf:referenceItem)?] Une entrée de référentiel (format FLASH).</xd:param> <xd:param name="code">[xs:string] Le code de la métadonnée à retourner (exemples : "libelleComplet", "libelleAbrege", "CXML_Id", etc.).</xd:param> <xd:param name="type">[xs:string] Le type de contenu à récupérer.</xd:param> <xd:return>[item()*] Le contenu de la métadonnée, si elle a été trouvée.</xd:return> </xd:doc> <xsl:function name="xf:getRefEntryMetaContent" as="item()*"> <xsl:param name="refEntry" as="element(xf:referenceItem)?"/> <xsl:param name="code" as="xs:string"/> <xsl:param name="type" as="xs:string"/> <!-- Obtention de la métadonnée correspondant à $code (si elle existe) --> <xsl:variable name="referenceItemMeta" select="xf:getRefEntryMeta($refEntry,$code)" as="element(xf:meta)?"/> <!-- Récupération du contenu de la métadonnée (si elle existe et selon $type) --> <xsl:sequence select="xf:getMetaContent($referenceItemMeta,$type)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Signature à 4 arguments de la fonction xf:getRefEntryMetaValue($refEntry as element(xf:referenceItem), $code as xs:string)</xd:p> <xd:p>Retourne la valeur textuelle d'une métadonnée liée à une entrée de référentiel.</xd:p> <xd:p>Interroge le référentiel FLASH <xd:ref name="refXML" type="parameter">$refXML</xd:ref> et retourne la valeur de la métadonnée dont le code est <xd:ref name="code" type="parameter">$code</xd:ref> pour l'entrée <xd:ref name="entryId" type="parameter">$entryId</xd:ref>.</xd:p> <xd:p>Fait appel à la fonction xf:getMetaContent($meta as element(xf:meta?), $type as xs:string) as item()*.</xd:p> </xd:desc> <xd:param name="refXML">[element(xf:referenceTable)] Le référentiel XML (format FLASH).</xd:param> <xd:param name="entryId">[xs:string] L'ID de l'entrée de référentiel.</xd:param> <xd:param name="code">[xs:string] Le code de la métadonnée à retourner (exemples : "libelleComplet", "libelleAbrege", "CXML_Id", etc.).</xd:param> <xd:param name="type">[xs:string] Le type de contenu à récupérer.</xd:param> <xd:return>[item()*] Le contenu de la métadonnée, si elle a été trouvée.</xd:return> </xd:doc> <xsl:function name="xf:getRefEntryMetaContent" as="item()*"> <xsl:param name="refXML" as="element(xf:referenceTable)"/> <xsl:param name="entryId" as="xs:string"/> <xsl:param name="code" as="xs:string"/> <xsl:param name="type" as="xs:string"/> <!-- Obtention de l'entrée de référentiel --> <xsl:variable name="referenceItem" select="xf:getRefEntry($refXML,$entryId)" as="element(xf:referenceItem)?"/> <!-- Récupération du contenu de la métadonnée (si elle existe et selon $type) --> <xsl:sequence select="xf:getRefEntryMetaContent($referenceItem,$code,$type)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne la valeur textuelle d'une métadonnée liée à une entrée de référentiel.</xd:p> <xd:p>Retourne la valeur de la métadonnée dont le code est <xd:ref name="code" type="parameter">$code</xd:ref> pour l'entrée <xd:ref name="refEntry" type="parameter">$refEntry</xd:ref>.</xd:p> </xd:desc> <xd:param name="refEntry">[element(xf:referenceItem)?] Une entrée de référentiel (format FLASH).</xd:param> <xd:param name="code">[xs:string] Le code de la métadonnée à retourner (exemples : "libelleComplet", "libelleAbrege", "CXML_Id", etc.).</xd:param> <xd:return>[xs:string*] La valeur (textuelle) de la métadonnée, si elle a été trouvée.</xd:return> </xd:doc> <xsl:function name="xf:getRefEntryMetaValue" as="xs:string*"> <xsl:param name="refEntry" as="element(xf:referenceItem)?"/> <xsl:param name="code" as="xs:string"/> <!-- Obtention de la métadonnée correspondant à $code (si elle existe) --> <xsl:variable name="referenceItemMeta" select="xf:getRefEntryMeta($refEntry,$code)" as="element(xf:meta)?"/> <!-- Récupération de la valeur de la métadonnée (si elle existe) --> <xsl:sequence select="xf:getMetaValue($referenceItemMeta)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Signature à 3 arguments de la fonction xf:getRefEntryMetaValue($refEntry as element(xf:referenceItem), $code as xs:string)</xd:p> <xd:p>Retourne la valeur textuelle d'une métadonnée liée à une entrée de référentiel.</xd:p> <xd:p>Interroge le référentiel FLASH <xd:ref name="refXML" type="parameter">$refXML</xd:ref> et retourne la valeur de la métadonnée dont le code est <xd:ref name="code" type="parameter">$code</xd:ref> pour l'entrée <xd:ref name="entryId" type="parameter">$entryId</xd:ref>.</xd:p> </xd:desc> <xd:param name="refXML">[element(xf:referenceTable)] Le référentiel XML (format FLASH).</xd:param> <xd:param name="entryId">[xs:string] L'ID de l'entrée de référentiel.</xd:param> <xd:param name="code">[xs:string] Le code de la métadonnée à retourner (exemples : "libelleComplet", "libelleAbrege", "CXML_Id", etc.).</xd:param> <xd:return>[xs:string*] La valeur (textuelle) de la métadonnée, si elle a été trouvée.</xd:return> </xd:doc> <xsl:function name="xf:getRefEntryMetaValue" as="xs:string*"> <xsl:param name="refXML" as="element(xf:referenceTable)"/> <xsl:param name="entryId" as="xs:string"/> <xsl:param name="code" as="xs:string"/> <!-- Obtention de l'entrée de référentiel --> <xsl:variable name="referenceItem" select="xf:getRefEntry($refXML,$entryId)" as="element(xf:referenceItem)?"/> <!-- Récupération de la valeur de la métadonnée (si elle existe) --> <xsl:sequence select="xf:getRefEntryMetaValue($referenceItem,$code)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne le contenu de l'enfant <xf:value> d'une métadonnée liée à une entrée de référentiel.</xd:p> <xd:p>Retrouve la métadonnée dont le code est <xd:ref name="code" type="parameter">$code</xd:ref> pour l'entrée <xd:ref name="refEntry" type="parameter">$refEntry</xd:ref>.</xd:p> <xd:p>Fait appel à la fonction xf:getMetaValueContent($meta as element(xf:meta?)) as item()*.</xd:p> </xd:desc> <xd:param name="refEntry">[element(xf:referenceItem)?] Une entrée de référentiel (format FLASH).</xd:param> <xd:param name="code">[xs:string] Le code de la métadonnée à retourner (exemples : "libelleComplet", "libelleAbrege", "CXML_Id", etc.).</xd:param> <xd:return>[item()*] Le contenu de l'élément <xf:value> de la métadonnée, si elle a été trouvée.</xd:return> </xd:doc> <xsl:function name="xf:getRefEntryMetaValueContent" as="item()*"> <xsl:param name="refEntry" as="element(xf:referenceItem)?"/> <xsl:param name="code" as="xs:string"/> <!-- Obtention de la métadonnée correspondant à $code (si elle existe) --> <xsl:variable name="referenceItemMeta" select="xf:getRefEntryMeta($refEntry,$code)" as="element(xf:meta)?"/> <!-- Récupération de la valeur de la métadonnée (si elle existe) --> <xsl:sequence select="xf:getMetaValueContent($referenceItemMeta)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Signature à 3 arguments de la fonction xf:getRefEntryMetaValueContent($refEntry as element(xf:referenceItem), $code as xs:string)</xd:p> <xd:p>Retourne le contenu de l'enfant <xf:value> d'une métadonnée liée à une entrée de référentiel.</xd:p> <xd:p>Interroge le référentiel FLASH <xd:ref name="refXML" type="parameter">$refXML</xd:ref> et retrouve la métadonnée dont le code est <xd:ref name="code" type="parameter">$code</xd:ref> pour l'entrée <xd:ref name="entryId" type="parameter">$entryId</xd:ref>.</xd:p> </xd:desc> <xd:param name="refXML">[element(xf:referenceTable)] Le référentiel XML (format FLASH).</xd:param> <xd:param name="entryId">[xs:string] L'ID de l'entrée de référentiel.</xd:param> <xd:param name="code">[xs:string] Le code de la métadonnée à retourner (exemples : "libelleComplet", "libelleAbrege", "CXML_Id", etc.).</xd:param> <xd:return>[item()*] Le contenu de l'élément <xf:value> de la métadonnée, si elle a été trouvée.</xd:return> </xd:doc> <xsl:function name="xf:getRefEntryMetaValueContent" as="item()*"> <xsl:param name="refXML" as="element(xf:referenceTable)"/> <xsl:param name="entryId" as="xs:string"/> <xsl:param name="code" as="xs:string"/> <!-- Obtention de l'entrée de référentiel --> <xsl:variable name="referenceItem" select="xf:getRefEntry($refXML,$entryId)" as="element(xf:referenceItem)?"/> <!-- Récupération du contenu de la métadonnée (si elle existe) --> <xsl:sequence select="xf:getRefEntryMetaValueContent($referenceItem,$code)"/> </xsl:function> <!--+==================================================+ | FONCTIONS / Fonctions liées aux ID / liens FLASH | | -> Normalisation des ID cibles des liens | | -> Test de la résolution des liens | +==================================================+--> <xd:doc> <xd:desc> <xd:p>Fonction utilitaire qui retourne une représentation unifiée d'un ID cible de lien FLASH (ou ID/IDREF de ciblage).</xd:p> <xd:p>Prend en entrée un élément de référence (xf:ref) et concatène les attributs @xf:targetResId et @xf:idRef.</xd:p> <xd:p>Le passage par cette fonction permet de comparer facilement des liens lorsque les deux attributs de ciblage sont utilisés, de créer des clés basées sur les cibles, etc.</xd:p> </xd:desc> <xd:param name="ref">[element(xf:ref)?] Un élément de référence xf:ref.</xd:param> <xd:return>[xs:string?] L'IDREF de ciblage, concaténation de @xf:targetResId et @xf:idRef.</xd:return> </xd:doc> <xsl:function name="xf:getFlashTargetIdRef" as="xs:string"> <xsl:param name="ref" as="element(xf:ref)?"/> <xsl:sequence select="xf:makeTargetId($ref/@xf:targetResId,$ref/@xf:idRef)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Fonction utilitaire qui retourne une représentation unifiée d'un ID cible de lien NON-FLASH (ou ID/IDREF de ciblage).</xd:p> <xd:p>Prend en entrée un élément de référence (xf:ref) et concatène les attributs @xf:targetResId et @idRef.</xd:p> <xd:p>Le passage par cette fonction permet de comparer facilement des liens lorsque les deux attributs de ciblage sont utilisés, de créer des clés basées sur les cibles, etc.</xd:p> </xd:desc> <xd:param name="ref">[element(xf:ref)?] Un élément de référence xf:ref.</xd:param> <xd:return>[xs:string?] L'IDREF de ciblage, concaténation de @xf:targetResId et @idRef.</xd:return> </xd:doc> <xsl:function name="xf:getNonFlashTargetIdRef" as="xs:string"> <xsl:param name="ref" as="element(xf:ref)?"/> <xsl:sequence select="xf:makeTargetId($ref/@xf:targetResId,$ref/@idRef)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Fonction utilitaire qui retourne une représentation unifiée d'un ID cible de lien FLASH ou NON-FLASH (ou ID/IDREF de ciblage).</xd:p> <xd:p>Prend en entrée un élément de référence (xf:ref) et concatène les attributs @xf:targetResId et @xf:idRef/@idRef.</xd:p> <xd:p>Le passage par cette fonction permet de comparer facilement des liens lorsque les deux attributs de ciblage sont utilisés, de créer des clés basées sur les cibles, etc.</xd:p> </xd:desc> <xd:param name="ref">[element(xf:ref)?] Un élément de référence xf:ref.</xd:param> <xd:return>[xs:string?] L'IDREF de ciblage, concaténation de @xf:targetResId et @xf:idRef/@idRef.</xd:return> </xd:doc> <xsl:function name="xf:getTargetIdRef" as="xs:string"> <xsl:param name="ref" as="element(xf:ref)?"/> <xsl:sequence select="xf:makeTargetId($ref/@xf:targetResId,($ref/@xf:idRef,$ref/@idRef)[1])"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Fonction utilitaire, qui concatène deux valeurs dans le but d'obtenir une représentation unifiée d'un ID cible (ou ID de ciblage).</xd:p> <xd:p>Les deux arguments sont typiquement des valeurs d'attributs xf:ref/@xf:targetResId / xf:ref/@xf:idRef (ou @idRef).</xd:p> </xd:desc> <xd:param name="targetResId">[xs:string?] Un ID de base, correspondant à un @xf:targetResId.</xd:param> <xd:param name="idRef">[xs:string?] Un ID à concaténer, correspondant à un @xf:idRef/@idRef.</xd:param> <xd:return>[xs:string?] L'ID de ciblage (ou une séquence vide, si les deux arguments sont des séquences vides).</xd:return> </xd:doc> <xsl:function name="xf:makeTargetId" as="xs:string"> <xsl:param name="targetResId" as="xs:string?"/> <xsl:param name="idRef" as="xs:string?"/> <xsl:sequence select="string-join(($targetResId,$idRef),'/')"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Calcule "l'ID de ciblage" d'un élément donné, obtenu à partir de l'attribut @xf:id de l'EE parente et de l'attribut @xf:id ou @id de l'élément courant.</xd:p> <xd:p>Cet ID calculé permettra de déterminer si l'élément est la cible d'un lien (xf:ref -> @xf:targetResId + @xf:idRef/@idRef).</xd:p> </xd:desc> <xd:param name="elt">[element()] L'élément courant, dont on souhaite déterminer l'ID de ciblage.</xd:param> <xd:return>[xs:string] L'ID de ciblage calculé de l'élément.</xd:return> </xd:doc> <xsl:function name="xf:getElementTargetId" as="xs:string"> <xsl:param name="elt" as="element()"/> <!-- ID de l'EE --> <xsl:variable name="targetResId" select="$elt/ancestor-or-self::xf:editorialEntity[1]/@xf:id" as="xs:string?"/> <!-- ID de l'élément (s'il n'est pas une EE) - generate-id() si pas de valeur, pour pouvoir utiliser une indexation via des keys (-> type 'getElementByTargetId') --> <xsl:variable name="id" select="$elt[not(self::xf:editorialEntity)]/(@xf:id,@id,generate-id())[1]" as="xs:string?"/> <!-- Obtention de l'ID de ciblage de l'élément --> <xsl:sequence select="xf:makeTargetId($targetResId,$id)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne la partie correspondant au @xf:targetResId depuis un ID de ciblage.</xd:p> </xd:desc> <xd:param name="targetId">[xs:string] L'ID de ciblage complet (@xf:targetResId + @xf:idRef ou @idRef).</xd:param> <xd:return>[xs:string] La partie de <xd:ref name="targetId" type="parameter">$targetId</xd:ref> correspondant à un attribut de ciblage @xf:targetResId.</xd:return> </xd:doc> <xsl:function name="xf:getTargetResIdFromTargetId" as="xs:string?"> <xsl:param name="targetId" as="xs:string"/> <xsl:sequence select="tokenize($targetId,'/')[1]"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne la partie correspondant au @xf:idRef / @idRef depuis un ID de ciblage.</xd:p> </xd:desc> <xd:param name="targetId">[xs:string] L'ID de ciblage complet (@xf:targetResId + @xf:idRef ou @idRef).</xd:param> <xd:return>[xs:string] La partie de <xd:ref name="targetId" type="parameter">$targetId</xd:ref> correspondant à un attribut de ciblage @xf:idRef / @idRef.</xd:return> </xd:doc> <xsl:function name="xf:getIdFromTargetId" as="xs:string?"> <xsl:param name="targetId" as="xs:string"/> <xsl:sequence select="tokenize($targetId,'/')[2]"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Détermine si un lien (un élément lié à une relation pointant vers une cible interne/externe - ex. : renvoiAutrui, refDoc, renvoi, etc.) est résolu.</xd:p> <xd:p>Si c'est le cas, les attributs @xf:targetResId, @xf:idRef/@idRef de sa relation (portés par xf:ref) contiennent des IDs.</xd:p> <xd:p>Si ce n'est pas le cas, ils contiennent une query, sous la forme "{query:...}".</xd:p> <xd:p>TODO : Fonction à nettoyer quand l'ECM saura gérer les queries.</xd:p> </xd:desc> <xd:param name="e">[element()] L'élément de lien à tester.</xd:param> <xd:return>[xs:boolean] Le résultat du test de résolution du lien.</xd:return> </xd:doc> <xsl:function name="xf:isResolvedLink" as="xs:boolean"> <xsl:param name="e" as="element()"/> <xsl:variable name="top" select="$e/ancestor::xf:editorialEntity[1]" as="element(xf:editorialEntity)"/> <!-- Relation (éventuelle) associée à l'élément de lien --> <xsl:variable name="relation" select="key('xf:getRelationById',$e/@xf:idRef,$top)" as="element(xf:relation)?"/> <xsl:choose> <!-- Pas de relation associée TODO : A supprimer ? Pas un cas réel ? --> <xsl:when test="not($relation)"> <xsl:sequence select="false()"/> </xsl:when> <!-- Les attributs de xf:ref sont vides TODO : A supprimer ? Pas un cas réel ? --> <xsl:when test="xf:getTargetIdRef($relation/xf:ref) = ('','/')"> <xsl:sequence select="false()"/> </xsl:when> <!-- xf:ref/@xf:targetResId = 'NULL' TODO : A supprimer ? Temporaire tant que l'ECM ne génère pas de query ! --> <xsl:when test="$relation/xf:ref/@xf:targetResId = 'NULL'"> <xsl:sequence select="false()"/> </xsl:when> <!-- xf:ref/@xf:targetResId = '{historicalId:xxx}' --> <xsl:when test="$relation/xf:ref/xf:isHistoricalIdRef(@xf:targetResId)"> <xsl:sequence select="false()"/> </xsl:when> <xsl:otherwise> <!-- Si le lien n'est pas résolu, les attributs de xf:ref contiennent une query sous la forme "{query:}" --> <xsl:sequence select="not(some $ref in ($relation/xf:ref/(@xf:targetResId,@xf:idRef,@idRef)) satisfies xf:isQueryRef($ref))"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc> <xd:desc> <xd:p>Détermine si une référence donnée (<xd:ref name="ref" type="parameter">$ref</xd:ref>) est une query, par opposition à un ID résolu.</xd:p> <xd:p>Typiquement, <xd:ref name="ref" type="parameter">$ref</xd:ref> est la valeur d'un attribut xf:ref/@xf:targetResId, xf:ref/@xf:idRef ou xf:ref/@idRef.</xd:p> </xd:desc> <xd:param name="ref">[xs:string?] Une référence (la valeur d'un attribut @xf:targetResId par exemple).</xd:param> <xd:return>[xs:boolean] Le résultat du test.</xd:return> </xd:doc> <xsl:function name="xf:isQueryRef" as="xs:boolean"> <xsl:param name="ref" as="xs:string?"/> <xsl:sequence select="starts-with(normalize-space($ref),'{query:')"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Détermine si une référence donnée (<xd:ref name="ref" type="parameter">$ref</xd:ref>) fait référence à un ID historique.</xd:p> <xd:p>Typiquement, <xd:ref name="ref" type="parameter">$ref</xd:ref> est la valeur d'un attribut xf:ref/@xf:targetResId.</xd:p> </xd:desc> <xd:param name="ref">[xs:string?] Une référence (la valeur d'un attribut @xf:targetResId par exemple).</xd:param> <xd:return>[xs:boolean] Le résultat du test.</xd:return> </xd:doc> <xsl:function name="xf:isHistoricalIdRef" as="xs:boolean"> <xsl:param name="ref" as="xs:string?"/> <xsl:sequence select="starts-with(normalize-space($ref),'{historicalId:')"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne la valeur d'un ID historique (typiquement construit depuis la transformation SAS et stocké dans un attribut @xf:historicalId dans l'ECM), en tronquant un éventuel préfixe.</xd:p> </xd:desc> <xd:param name="prefix">[xs:string] Le préfixe à tronquer (ex. : "efl_").</xd:param> <xd:param name="historicalId">[xs:string?] L'ID historique tel que stocké dans l'ECM (ex. : valeur d'un @xf:historicalId).</xd:param> <xd:return>[xs:string?] La valeur de l'ID historique après troncature.</xd:return> </xd:doc> <xsl:function name="xf:getHistoricalIdValue" as="xs:string?"> <xsl:param name="prefix" as="xs:string"/> <xsl:param name="historicalId" as="xs:string?"/> <xsl:sequence select="if (starts-with($historicalId,$prefix)) then (substring-after($historicalId,$prefix)) else ($historicalId)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Retourne le nom d'un fichier média, tel qu'appelé dans un attribut @xf:targetResId.</xd:p> <xd:p>L'ECM sérialise le nom du fichier sous la forme : @xf:targetResId="{filename:xxx} - où "xxx" est un nom de fichier avec son extension.</xd:p> <xd:p>Ce genre de notation est utilisé dans les métadonnées de type média, par exemple.</xd:p> </xd:desc> <xd:param name="targetResIdVal">[xs:string?] La valeur de l'attribut @targetResId.</xd:param> <xd:return>[xs:string?] Le nom du fichier.</xd:return> </xd:doc> <xsl:function name="xf:getMediaFileNameFromTargetResId" as="xs:string?"> <xsl:param name="targetResIdVal" as="xs:string?"/> <xsl:sequence select="replace($targetResIdVal,'^\{filename:(.+?)\}$','$1')"/> </xsl:function> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" exclude-result-prefixes="#all" version="3.0" xml:lang="en"> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>Generic XSL functions/templates library used at ELS</xd:p> </xd:desc> </xd:doc> <!--<xsl:import href="functx.xsl"/> already imported within modules--> <xsl:import href="els-common_constants.xsl"/> <xsl:import href="els-common_dates.xsl"/> <xsl:import href="els-common_strings.xsl"/> <xsl:import href="els-common_xml.xsl"/> <xsl:import href="els-common_files.xsl"/> <xsl:import href="els-common_convert-cast.xsl"/> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" exclude-result-prefixes="#all" version="3.0" xml:lang="en"> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>ELS-COMMON lib : module "CONSTANTS"</xd:p> </xd:desc> </xd:doc> <!--=================================================== --> <!-- OUTPUT --> <!--=================================================== --> <xsl:output name="els:xml" method="xml"/> <xsl:output name="els:xml.indent" method="xml" indent="yes"/> <xsl:output name="els:text" method="text"/> <!--=================================================== --> <!-- COMMON VAR --> <!--=================================================== --> <xd:doc> <xd:desc> <xd:p>double/simple quot variable, might be usefull within a concat for example</xd:p> </xd:desc> </xd:doc> <xsl:variable name="els:dquot" as="xs:string"> <xsl:text>"</xsl:text> </xsl:variable> <xsl:variable name="els:quot" as="xs:string"> <xsl:text>'</xsl:text> </xsl:variable> <xd:p>Variable "regAnySpace" : matches any spaces (non-break space, thin space, etc.)</xd:p> <xsl:variable name="els:regAnySpace" select="'\p{Z}'" as="xs:string"/> <xd:p>Variable "regAnyPonctuation" : matches any ponctuation (point, coma, semicolon, etc.)</xd:p> <xd:p>(cf. http://www.regular-expressions.info/unicode.html)</xd:p> <xsl:variable name="els:regAnyPonctuation" select="'\p{P}'" as="xs:string"/> <xd:p>Variable "regAnyNumber : match any number</xd:p> <xd:p>(cf. http://www.regular-expressions.info/unicode.html)</xd:p> <xsl:variable name="els:regAnyNumber" select="'\p{N}'" as="xs:string"/> <xd:p>Variable "regAnyLetter : match any letter</xd:p> <xd:p>(cf. http://www.regular-expressions.info/unicode.html)</xd:p> <xsl:variable name="els:regAnyLetter" select="'\p{L}'" as="xs:string"/> <xd:p>Variable "end of word" (equivalent to "\b" in regex)</xd:p> <xsl:variable name="els:regWordBoundery" select="concat($els:regAnySpace, '|', $els:regAnyPonctuation)" as="xs:string"/> <xd:doc> <xd:desc>TYPOGRAPHIC SPACES</xd:desc> <xd:p>Every spaces from the largest to the thinest : &#x2000; (same width as letter "M") => &#x200b; (zero width space - breakable)</xd:p> <xd:p>Tip : Use the software "SC UNIPAD" to see and convert spaces. cf. http://theme.unblog.fr/2007/05/18/ponctuation/</xd:p> </xd:doc> <xsl:variable name="els:EN_QUAD" select="' '" as="xs:string"/><!--(1/8 cadratin)= " "--> <xsl:variable name="els:NARROW_NO_BREAK_SPACE" select="' '" as="xs:string"/><!--= " "--> <xsl:variable name="els:NO_BREAK_SPACE" select="' '" as="xs:string"/><!-- = " "--> <xsl:variable name="els:ZERO_WIDTH_SPACE" select="''" as="xs:string"/><!-- = ""--> <xsl:variable name="els:ZERO_WIDTH_NO_BREAK_SPACE" select="''" as="xs:string"/><!--(non matché par '\p{Z}') = ""--> <xsl:variable name="els:HAIR_SPACE" select="' '" as="xs:string"/><!--("espace ultra fine sécable") = " "--> <xsl:variable name="els:PONCTUATION_SPACE" select="' '" as="xs:string"/><!--(1/3 de cadratin ?) = " "--> <xsl:variable name="els:THIN_SPACE" select="' '" as="xs:string"/><!--(espaces fine ou quart de cadratin?) = " "--> <xsl:variable name="els:EN_SPACE" select="' '" as="xs:string"/><!-- https://www.cs.sfu.ca/~ggbaker/reference/characters/#space --> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" exclude-result-prefixes="#all" version="3.0" xml:lang="en"> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>ELS-COMMON lib : module "DATES" utilities</xd:p> </xd:desc> </xd:doc> <xsl:import href="els-common_constants.xsl"/> <xd:doc>Variables for giving Month in any language</xd:doc> <xsl:variable name="els:months.fr" select="('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre')" as="xs:string+"/> <xsl:variable name="els:monthsShort.fr" select="('janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juill.', 'août', 'sept.', 'oct.', 'nov.', 'déc.')" as="xs:string+"/> <xd:doc>Get the current date as string in ISO format YYYY-MM-DD</xd:doc> <xsl:function name="els:getCurrentIsoDate" as="xs:string"> <xsl:sequence select="format-dateTime(current-dateTime(),'[Y0001]-[M01]-[D01]')"/> </xsl:function> <xd:doc>Get the year as string from any ISO date : YYYY-MM-DD would get "YYYY"</xd:doc> <xsl:function name="els:getYearFromIsoDate" as="xs:string"> <xsl:param name="isoDate" as="xs:string"/> <xsl:choose> <xsl:when test="els:isIsoDate($isoDate)"> <xsl:value-of select="tokenize($isoDate, '-')[1]"/> </xsl:when> <xsl:otherwise> <xsl:message>[ERROR][els:getYearFromIsoDate] param $isoDate="<xsl:value-of select="$isoDate"/>" is not an ISO format "YYYY-MM-DD"</xsl:message> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc>Get the month number as string from any ISO date : YYYY-MM-DD would get "MM"</xd:doc> <xsl:function name="els:getMonthFromIsoDate" as="xs:string"> <xsl:param name="isoDate" as="xs:string"/> <xsl:choose> <xsl:when test="els:isIsoDate($isoDate)"> <xsl:value-of select="tokenize($isoDate, '-')[2]"/> </xsl:when> <xsl:otherwise> <xsl:message>[ERROR][els:getMonthFromIsoDate] param $isoDate="<xsl:value-of select="$isoDate"/>" is not an ISO format "YYYY-MM-DD"</xsl:message> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc>Get the day number as string from any ISO date : YYYY-MM-DD would get "DD"</xd:doc> <xsl:function name="els:getDayFromIsoDate" as="xs:string"> <xsl:param name="isoDate" as="xs:string"/> <xsl:choose> <xsl:when test="els:isIsoDate($isoDate)"> <xsl:value-of select="tokenize($isoDate, '-')[3]"/> </xsl:when> <xsl:otherwise> <xsl:message>[ERROR][els:getDayFromIsoDate] param $isoDate="<xsl:value-of select="$isoDate"/>" is not an ISO format "YYYY-MM-DD"</xsl:message> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc>Determine if a string is of format ISO date "YYYY-MM-DD"</xd:doc> <xsl:function name="els:isIsoDate" as="xs:boolean"> <xsl:param name="dateString" as="xs:string"/> <xsl:sequence select="matches($dateString, '^\d\d\d\d-\d\d-\d\d$')"/> </xsl:function> <xd:doc>Returns an ISO date (xs:date) from a string whose format is "YYYYMMDD"</xd:doc> <xsl:function name="els:makeIsoDateFromYYYYMMDD" as="xs:string?"> <xsl:param name="date" as="xs:string"/> <xsl:variable name="day" select="substring($date, 7, 2)" as="xs:string"/> <xsl:variable name="month" select="substring($date, 5, 2)" as="xs:string"/> <xsl:variable name="year" select="number(substring($date, 1, 4))" as="xs:double"/> <xsl:sequence select="els:getIsoDateFromString(concat($year, '-', $month, '-', $day))"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Returns an ISO date (xs:date) from a string (typically: a serialized date), formatted as YYYY-MM-DD.</xd:p> <xd:p>The input parameter (<xd:ref name="date" type="parameter">$date</xd:ref>) is tested and must be castable either as xs:date or xs:dateTime.</xd:p> <xd:p>If the input parameter can be casted as xs:dateTime, only the substring corresponding to the date part is returned.</xd:p> </xd:desc> <xd:param name="date">[xs:string] A string, which must be a serialized xs:date or xs:dateTime.</xd:param> <xd:return>[xs:string?] The ISO date value of the input string.</xd:return> </xd:doc> <xsl:function name="els:getIsoDateFromString" as="xs:string?"> <xsl:param name="date" as="xs:string"/> <xsl:choose> <xsl:when test="$date castable as xs:dateTime"> <xsl:value-of select="format-dateTime($date cast as xs:dateTime,'[Y0001]-[M01]-[D01]')"/> </xsl:when> <xsl:when test="$date castable as xs:date"> <xsl:value-of select="format-date($date cast as xs:date,'[Y0001]-[M01]-[D01]')"/> </xsl:when> <xsl:otherwise> <xsl:message>[ERROR][els:getIsoDateFromString] The input date format is not recognized : '<xsl:value-of select="$date"/>'.</xsl:message> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc>1 arg signature of els:verbalizeMonthFromNum : default language is "french"</xd:doc> <xsl:function name="els:verbalizeMonthFromNum" as="xs:string"> <xsl:param name="monthNumString" as="xs:string"/> <xsl:sequence select="els:verbalizeMonthFromNum($monthNumString, $els:months.fr)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Verbalize a month as number to a string</xd:p> </xd:desc> <xd:param name="monthNumber">[String] The month number as string "XX" or "X"</xd:param> <xd:param name="months.verbalized">[String+] All months verbalized in the good language</xd:param> <xd:return>[String] The verbalized month</xd:return> </xd:doc> <xsl:function name="els:verbalizeMonthFromNum" as="xs:string"> <xsl:param name="monthNumString" as="xs:string"/> <xsl:param name="months.verbalized" as="xs:string+"/> <xsl:variable name="monthNumInt" select="if($monthNumString castable as xs:integer) then(xs:integer($monthNumString)) else(0)" as="xs:integer"/> <xsl:variable name="result" select="$months.verbalized[$monthNumInt]" as="xs:string?"/> <xsl:choose> <xsl:when test="exists($result)"> <xsl:sequence select="$result"/> </xsl:when> <xsl:otherwise> <xsl:text>[ErreurMois]</xsl:text> <xsl:message>[ERROR][els:verbalizeMonthFromNum] Unable to get the month string from month number '<xsl:value-of select="$monthNumString"/>'</xsl:message> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc>1 arg signature of els:getMonthNumFromVerbalizeMonth : default language is "french"</xd:doc> <xsl:function name="els:getMonthNumFromVerbalizeMonth" as="xs:integer"> <xsl:param name="monthString" as="xs:string"/> <xsl:sequence select="els:getMonthNumFromVerbalizeMonth($monthString, $els:months.fr)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Get the month num as integer from its verbalization</xd:p> </xd:desc> <xd:param name="monthString">[String] The month string (ex : "january", "février", etc.)</xd:param> <xd:param name="months.verbalized">[String+] All months as string verbalized in the good language</xd:param> <xd:return>[String] The verbalized month</xd:return> </xd:doc> <xsl:function name="els:getMonthNumFromVerbalizeMonth" as="xs:integer"> <xsl:param name="monthString" as="xs:string"/> <xsl:param name="months.verbalized" as="xs:string+"/> <xsl:variable name="result" select="index-of($months.verbalized, $monthString)" as="xs:integer*"/> <xsl:choose> <xsl:when test="count($result) = 1"> <xsl:sequence select="$result"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="0"/> <xsl:message>[ERROR][els:getMonthNumFromVerbalizeMonth] Unable to get an integer representation of the month from the string '<xsl:value-of select="$monthString"/>' : <xsl:value-of select="count($result)"/> match.</xsl:message> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc> <xd:desc> <xd:p>Convert a string with format "JJ/MM/AAAA" (or "JJ-MM-AAAA" or "JJ/MM/AA") to a string representing an ISO date format "AAAA-MM-JJ"</xd:p> <xd:param name="s">String to convert as iso date string</xd:param> <xd:param name="sep">string representing the separator "/" (or something els) within the original string ($s)</xd:param> </xd:desc> <xd:return>Iso date of $s as a xs:string (if the convesion fails, it will return the original $s string)</xd:return> </xd:doc> <xsl:function name="els:makeIsoDate" as="xs:string"> <xsl:param name="s" as="xs:string?"/> <xsl:param name="sep" as="xs:string"/> <xsl:variable name="sToken" select="tokenize($s, $sep)" as="xs:string*"/> <xsl:variable name="regJJMMAAAA" as="xs:string" select="concat('^\d\d', $sep, '\d\d', $sep, '\d\d\d\d$')"/> <xsl:variable name="regJJMMAA" as="xs:string" select="concat('^\d\d', $sep, '\d\d', $sep, '\d\d')"/> <xsl:choose> <!--If $s is empty, we can't do anything : return the empty string--> <xsl:when test="empty($s)"> <xsl:value-of select="''"/> </xsl:when> <!--If $sep is empty, we can't do anything : return the original string $s--> <xsl:when test="$sep = ''"> <xsl:value-of select="$s"/> </xsl:when> <!--The string $s format is correct "JJ/MM/AAAA" : convert it to "AAAA-MM-JJ" --> <xsl:when test="matches($s, $regJJMMAAAA)"> <xsl:value-of select="concat($sToken[3], '-', $sToken[2], '-', $sToken[1])"/> </xsl:when> <!--The string $s format is correct except the year which is on 2 digit "JJ/MM/AA" : convert it to "AAAA-MM-JJ" (trying to guess the century)--> <!--ASSUME : if AA is later than current AA, we consider AA was in the last century--> <xsl:when test="matches($s, $regJJMMAA)"> <xsl:variable name="currentAAAA" select="year-from-date(current-date())" as="xs:integer"/> <xsl:variable name="currentAA__" select="substring(string($currentAAAA), 1, 2) cast as xs:integer" as="xs:integer"/> <xsl:variable name="current__AA" select="substring(string($currentAAAA), 3, 2) cast as xs:integer" as="xs:integer"/> <xsl:variable name="AA" select="xs:integer($sToken[3])" as="xs:integer"/> <xsl:variable name="AAAA" select="if ($AA gt $current__AA) then (concat($currentAA__ -1, $AA)) else (concat($currentAA__, $AA))" as="xs:string"/> <xsl:value-of select="concat($AAAA, '-', $sToken[2], '-', $sToken[1])"/> </xsl:when> <!--Unknown format : return the original string $s--> <xsl:otherwise> <xsl:value-of select="$s"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xsl:function name="els:date-number-slash" as="xs:string"> <xsl:param name="date" as="xs:string"/> <xsl:variable name="jour" select="substring($date, 9, 2)" as="xs:string"/> <xsl:variable name="mois" select="substring($date, 6, 2)" as="xs:string"/> <xsl:variable name="annee" select="substring($date, 1, 4)" as="xs:string"/> <xsl:value-of select="concat($jour, '/',$mois, '/', $annee)"/> </xsl:function> <xsl:function name="els:date-number-dash" as="xs:string"> <xsl:param name="date" as="xs:string"/> <xsl:variable name="jour" select="substring($date, 9, 2)" as="xs:string"/> <xsl:variable name="mois" select="substring($date, 6, 2)" as="xs:string"/> <xsl:variable name="annee" select="substring($date, 1, 4)" as="xs:string"/> <xsl:value-of select="concat($jour, '-',$mois, '-', $annee)"/> </xsl:function> <xsl:function name="els:date-string" as="xs:string"> <xsl:param name="date" as="xs:string"/> <xsl:variable name="jour" select="number(substring($date, 9, 2))" as="xs:double"/> <xsl:variable name="mois" select="els:verbalizeMonthFromNum(substring($date, 6, 2))" as="xs:string"/> <xsl:variable name="annee" select="number(substring($date,1, 4))" as="xs:double"/> <xsl:value-of select="concat($jour, ' ',$mois, ' ', $annee)"/> </xsl:function> <xd:doc>1 arg signature of els:displayDate : default months list is $els:months.fr</xd:doc> <xsl:function name="els:displayDate" as="xs:string"> <xsl:param name="date" as="xs:string"/> <xsl:sequence select="els:displayDate($date, $els:months.fr)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Display a date at format YYYYMMDD to a verbalized date. Example: 19750910 => "10 Septembre 1975"</xd:p> </xd:desc> <xd:param name="date">[String] date a format YYYYMMDD</xd:param> <xd:param name="months.verbalized">[String] date</xd:param> </xd:doc> <xsl:function name="els:displayDate" as="xs:string"> <xsl:param name="date" as="xs:string"/> <xsl:param name="months.verbalized" as="xs:string+"/> <xsl:variable name="day" select="number(substring($date, 7, 2))" as="xs:double"/> <xsl:variable name="month" select="els:verbalizeMonthFromNum(substring($date, 5, 2), $months.verbalized)" as="xs:string"/> <xsl:variable name="year" select="number(substring($date, 1, 4))" as="xs:double"/> <xsl:value-of select="concat($day, ' ', $month, ' ', $year)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Convert a verbalized date with format "DD month YYYY" to the format "DD/MM/AAAA"</xd:p> <xd:param name="dateVerbalized">[String] verbalized date "DD Month YYYY"</xd:param> <xd:param name="shortMonth">[Boolean] determine if the "month" is in a short format or no (ex: janv. instead of janvier)</xd:param> </xd:desc> <xd:return>[String]The date with format "DD/MM/YYYY"</xd:return> </xd:doc> <!--FIXME : fonction format-date() le fait déjà ?--> <xsl:function name="els:date-string-to-number-slash" as="xs:string"> <xsl:param name="dateVerbalized" as="xs:string"/> <xsl:param name="shortMonth" as="xs:boolean"/> <xsl:choose> <xsl:when test="empty($dateVerbalized) or count(tokenize($dateVerbalized, $els:regAnySpace)) < 3"> <xsl:text>[ErreurDate]</xsl:text> <xsl:message>[ERROR][els:date-string-to-number-slash] Unable to get the date from '<xsl:value-of select="$dateVerbalized"/>'</xsl:message> </xsl:when> <xsl:otherwise> <xsl:variable name="dateVerbalized.token" select="tokenize($dateVerbalized, $els:regAnySpace)" as="xs:string*"/> <xsl:variable name="day" select="$dateVerbalized.token[1]" as="xs:string"/> <xsl:variable name="month" select="$dateVerbalized.token[2]" as="xs:string"/> <xsl:variable name="year" select="$dateVerbalized.token[3]" as="xs:string"/> <xsl:variable name="day" as="xs:string"> <xsl:choose> <xsl:when test="$day = '1er'"> <xsl:value-of select="'01'"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="format-number($day cast as xs:integer, '00')"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="month" select="format-number(els:getMonthNumFromVerbalizeMonth($month), '00')" as="xs:string"/> <xsl:value-of select="string-join(($day, $month, $year), '/')"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:p>1 arg signature of els:date-string-to-number-slash() - Default $shortMonth = false()</xd:p> <xsl:function name="els:date-string-to-number-slash" as="xs:string"> <xsl:param name="dateVerbalized" as="xs:string"/> <xsl:sequence select="els:date-string-to-number-slash($dateVerbalized, false())"/> </xsl:function> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" exclude-result-prefixes="#all" version="3.0" xml:lang="en"> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>ELS-COMMON lib : module "STRINGS" utilities</xd:p> </xd:desc> </xd:doc> <xsl:import href="els-common_constants.xsl"/> <xd:doc> <xd:desc> <xd:p>Perform successiv regex replacements on a string</xd:p> </xd:desc> <xd:param name="string">The string to work on</xd:param> <xd:param name="replace-list">An element els:replace-list with any els:replace as children. Example: <xd:pre> <replace-list flags="[optionnal attribut for regex flags]" xmlns="http://www.lefebvre-sarrut.eu/ns/els"> <replace flags="[optionnal attribut for regex flags]"> <pattern>[any regex]</pattern> <replacement>[replacement using $1, $2, etc. as regex-group replacement, like replace() third arg]</replacement> </replace> <replace flags="x"> <pattern>(x) (x) (x)</pattern> <replacement>Y$2Y</replacement> </replace> </replace-list> </xd:pre> </xd:param> <xd:return>The string after performing all regex replacements succesively</xd:return> </xd:doc> <xsl:function name="els:replace-multiple" as="xs:string"> <xsl:param name="string" as="xs:string"/> <xsl:param name="replace-list" as="element(els:replace-list)"/> <xsl:choose> <xsl:when test="empty($replace-list/els:replace)"> <xsl:sequence select="$string"/> </xsl:when> <xsl:otherwise> <xsl:variable name="replace-1" select="$replace-list/els:replace[1]" as="element(els:replace)"/> <!--Possible regex flags values: m: multiline mode s : dot-all mode i : case-insensitive x : ignore whitespace within the regex--> <xsl:variable name="flags" select="string($replace-1/ancestor-or-self::*[@flags][1]/@flags)" as="xs:string"/> <xsl:variable name="string.replaced" select="replace($string, string($replace-1/els:pattern), string($replace-1/els:replacement), $flags)" as="xs:string"/> <xsl:variable name="replace-list.new" as="element(els:replace-list)"> <els:replace-list> <xsl:copy-of select="$replace-list/@*"/> <xsl:sequence select="subsequence($replace-list/els:replace, 2)"/> </els:replace-list> </xsl:variable> <xsl:sequence select="els:replace-multiple($string.replaced, $replace-list.new)"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc> <xd:desc> <xd:p>DEPRECATED! Fonction qui fait les remplacements en regex récursivement</xd:p> <xd:p> Principe : Chaque regex va être passé SUCCESSIVEMENT sur le texte avec le type de traitement indiqué Attention l'ordre est important. Type de traitement : - remplace-brut = replace(string, regex) - remplace-group = replace('text1(reg1)', text1$1) - etc. Par exemple Type "remplace-group" signifie: on remplace par le ReplaceText, suivi par le 1er groupe reconnu par la regex; analogue pour "group-remplace-group", etc. </xd:p> </xd:desc> <xd:param name="Text">String à traiter</xd:param> <xd:param name="SequenceDeTriplets"> Un sequence d'éléments Triplets de la forme : <Triplet xmlns="http://www.lefebvre-sarrut.eu/ns/els"> <Type>remplace-brut</Type> <RegExp>[ ][ ]+</RegExp> <ReplaceText> </ReplaceText> </Triplet> <!--On préfère tout préfixer avec els: pour éviter tout problème de mélange de namespace (notamment lors de l'applatissement des xsl chaine xml)--> </xd:param> </xd:doc> <xsl:function name="els:reccursivReplace" as="xs:string*"> <xsl:param name="Text" as="xs:string?"/> <xsl:param name="SequenceDeTriplets" as="element(els:Triplet)*"/> <xsl:variable name="FirstTriplet" select="$SequenceDeTriplets[1]" as="element(els:Triplet)"/> <xsl:variable name="ResteDesTriplets" select="subsequence($SequenceDeTriplets,2)" as="element(els:Triplet)*"/> <xsl:message>[WARNING][ELSSIEXDC-13] "els:reccursivReplace" is DEPRECATED, please use the more generic function "els:replace-multiple" instead</xsl:message> <xsl:variable name="Type" select="$FirstTriplet/els:Type" as="element(els:Type)"/> <xsl:variable name="RegExp" select="$FirstTriplet/els:RegExp" as="element(els:RegExp)"/> <xsl:variable name="ReplaceText" select="$FirstTriplet/els:ReplaceText" as="element(els:ReplaceText)"/> <xsl:variable name="Result" as="xs:string*"> <xsl:choose> <xsl:when test="$Type = 'remplace-brut'"> <xsl:analyze-string regex="{$RegExp}" select="$Text"> <xsl:matching-substring> <xsl:value-of select="$ReplaceText"/> </xsl:matching-substring> <xsl:non-matching-substring> <xsl:sequence select="."/> </xsl:non-matching-substring> </xsl:analyze-string> </xsl:when> <xsl:when test="$Type = 'remplace-group-space'"> <xsl:analyze-string regex="{$RegExp}" select="$Text"> <xsl:matching-substring> <xsl:value-of select="$ReplaceText"/> <xsl:value-of select="regex-group(1)"/> <xsl:text> </xsl:text> </xsl:matching-substring> <xsl:non-matching-substring> <xsl:sequence select="."/> </xsl:non-matching-substring> </xsl:analyze-string> </xsl:when> <xsl:when test="$Type = 'remplace-group'"> <xsl:analyze-string regex="{$RegExp}" select="$Text"> <xsl:matching-substring> <xsl:value-of select="$ReplaceText"/> <xsl:value-of select="regex-group(1)"/> </xsl:matching-substring> <xsl:non-matching-substring> <xsl:sequence select="."/> </xsl:non-matching-substring> </xsl:analyze-string> </xsl:when> <xsl:when test="$Type = 'group'"> <xsl:analyze-string regex="{$RegExp}" select="$Text"> <xsl:matching-substring> <xsl:value-of select="regex-group(1)"/> </xsl:matching-substring> <xsl:non-matching-substring> <xsl:sequence select="."/> </xsl:non-matching-substring> </xsl:analyze-string> </xsl:when> <xsl:when test="$Type = 'space-group-remplace'"> <xsl:analyze-string regex="{$RegExp}" select="$Text"> <xsl:matching-substring> <xsl:text> </xsl:text> <xsl:value-of select="regex-group(1)"/> <xsl:value-of select="$ReplaceText"/> </xsl:matching-substring> <xsl:non-matching-substring> <xsl:sequence select="."/> </xsl:non-matching-substring> </xsl:analyze-string> </xsl:when> <xsl:when test="$Type = 'group-remplace'"> <xsl:analyze-string regex="{$RegExp}" select="$Text"> <xsl:matching-substring> <xsl:value-of select="regex-group(1)"/> <xsl:value-of select="$ReplaceText"/> </xsl:matching-substring> <xsl:non-matching-substring> <xsl:sequence select="."/> </xsl:non-matching-substring> </xsl:analyze-string> </xsl:when> <xsl:when test="$Type = 'group-remplace-group'"> <xsl:analyze-string regex="{$RegExp}" select="$Text"> <xsl:matching-substring> <xsl:value-of select="regex-group(1)"/> <xsl:value-of select="$ReplaceText"/> <xsl:value-of select="regex-group(2)"/> </xsl:matching-substring> <xsl:non-matching-substring> <xsl:sequence select="."/> </xsl:non-matching-substring> </xsl:analyze-string> </xsl:when> <xsl:when test="$Type = 'remplace-group-remplace-group'"> <xsl:analyze-string regex="{$RegExp}" select="$Text"> <xsl:matching-substring> <xsl:text> </xsl:text> <xsl:value-of select="regex-group(1)"/> <xsl:value-of select="$ReplaceText"/> <xsl:value-of select="regex-group(2)"/> </xsl:matching-substring> <xsl:non-matching-substring> <xsl:sequence select="."/> </xsl:non-matching-substring> </xsl:analyze-string> </xsl:when> </xsl:choose> </xsl:variable> <xsl:sequence select="if (empty($ResteDesTriplets)) then $Result else els:reccursivReplace($Result, $ResteDesTriplets)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Normalize the string: remove diacritic marks.</xd:p> <xd:p>Example: els:normalize-no-diacritic('éêèàœç')='eeeaœc'</xd:p> </xd:desc> <xd:param name="string"/> <xd:return>the <xd:b>string</xd:b> normalized</xd:return> </xd:doc> <xsl:function name="els:normalize-no-diacritic" as="xs:string"> <xsl:param name="string" as="xs:string"/> <xsl:sequence select="replace(normalize-unicode($string, 'NFD'), '[\p{M}]', '')"/> </xsl:function> <xd:doc> <xd:desc> <!--FIXME : difference with els:normalize-no-diacritic ? this function has been copied from Flash SAS EFL--> <xd:p>Normalize the string by removing accents</xd:p> </xd:desc> <xd:param name="string">The string to normalize</xd:param> </xd:doc> <xsl:function name="els:strip-accent" as="xs:string"> <xsl:param name="string" as="xs:string?"/> <xsl:value-of select="normalize-unicode(replace(normalize-unicode($string, 'NFD'), '\p{Mn}', ''), 'NFC')"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>"carriage return line feed" : generates N carriage return</xd:p> </xd:desc> <xd:param name="n">[Integer] number of carriage return to generate (should be positiv)</xd:param> </xd:doc> <xsl:function name="els:crlf" as="xs:string*"> <xsl:param name="n" as="xs:integer"/> <!--Ignore negativ $n--> <xsl:if test="$n gt 0"> <xsl:for-each select="1 to $n"> <xsl:text> </xsl:text> </xsl:for-each> </xsl:if> </xsl:function> <xd:doc>0 args Signature for els:crlf() : by default only one carriage return</xd:doc> <xsl:function name="els:crlf" as="xs:string"> <xsl:sequence select="els:crlf(1)"/> </xsl:function> <xd:doc>1 args Signature for els:getFirstChar : by default the first 1 character</xd:doc> <xsl:function name="els:getFirstChar" as="xs:string"> <xsl:param name="s" as="xs:string"/> <!--<xsl:value-of select="substring($s,1,1)"/>--> <xsl:sequence select="els:getFirstChar($s,1)"/> </xsl:function> <xd:doc>Get the first $n characters of a string</xd:doc> <xsl:function name="els:getFirstChar" as="xs:string"> <xsl:param name="s" as="xs:string"/> <xsl:param name="n" as="xs:integer"/> <xsl:value-of select="substring($s,1,$n)"/> </xsl:function> <xd:doc>Get the rest of the string after removing the first character</xd:doc> <xsl:function name="els:getStringButFirstChar" as="xs:string"> <xsl:param name="s" as="xs:string"/> <xsl:value-of select="substring($s,2)"/> </xsl:function> <xd:doc>Express any string with a capital as first letter, force the rest letters in lowercase</xd:doc> <xsl:function name="els:capFirst_lowercase" as="xs:string"> <xsl:param name="s" as="xs:string"/> <xsl:value-of select="concat(upper-case(els:getFirstChar($s)),lower-case(els:getStringButFirstChar($s)))"/> </xsl:function> <xd:doc>Express any string with a capital as first letter, let the rest letters as is</xd:doc> <xsl:function name="els:capFirst" as="xs:string"> <xsl:param name="s" as="xs:string"/> <xsl:value-of select="concat(upper-case(els:getFirstChar($s)), els:getStringButFirstChar($s))"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Determin if a string is kind of empty considering any whitespace as empty characters</xd:p> </xd:desc> <xd:param name="s">Any string</xd:param> <xd:return>Boolean : true() if $s is the empty string '' or if it only contains whitespaces, else false()</xd:return> </xd:doc> <xsl:function name="els:is-empty-or-whitespace" as="xs:boolean"> <xsl:param name="s" as="xs:string?"/> <xsl:sequence select="matches($s, concat('^', $els:regAnySpace, '*$'))"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Return the string value of a node, normalizing white-spaces for each descendant text()</xd:p> <xd:p>The default separator between 2 text() is an espace, it can be overrided</xd:p> </xd:desc> <xd:param name="node">Any node (but it makes sens if the node has text() descendants)</xd:param> <xd:param name="separator">Separator between text() nodes</xd:param> <xd:return>Normalize string value of the node</xd:return> </xd:doc> <xsl:function name="els:normalized-string" as="xs:string"> <xsl:param name="node" as="node()?"/> <xsl:param name="separator" as="xs:string"/> <xsl:sequence select="string-join($node/descendant::text()[normalize-space(.)], $separator)"/> </xsl:function> <xd:doc>By default the separator is a whitespace character (just like <xsl:value-of)</xd:doc> <xsl:function name="els:normalized-string" as="xs:string"> <xsl:param name="node" as="node()?"/> <xsl:sequence select="els:normalized-string($node, ' ')"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Check the text existance of an element except his children</xd:p> </xd:desc> <xd:param name="e">element to check</xd:param> <xd:return>true() if there is not texte, otherwise false()</xd:return> </xd:doc> <xsl:function name="els:hasNoTextChildExceptWhiteSpace" as="xs:boolean"> <xsl:param name="e" as="element()"/> <xsl:sequence select="els:is-empty-or-whitespace(normalize-space(string-join($e/text(), '')))"/> </xsl:function> <!--=====================--> <!-- MODE els:UPPERCASE --> <!--=====================--> <!--a specific mode to go uppercase on text keeping existing inline elements--> <xsl:template match="text()" mode="els:uppercase" priority="1"> <xsl:value-of select="upper-case(.)"/> </xsl:template> <xsl:template match="node() | @*" mode="els:uppercase"> <xsl:copy copy-namespaces="no"> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> <!--=====================--> <!-- MODE els:LOWERCASE --> <!--=====================--> <!--a specific mode to go lowercase on text keeping existing inline elements--> <xsl:template match="text()" mode="els:lowercase" priority="1"> <xsl:value-of select="lower-case(.)"/> </xsl:template> <xsl:template match="node() | @*" mode="els:lowercase"> <xsl:copy copy-namespaces="no"> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saxon="http://saxon.sf.net/" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" exclude-result-prefixes="#all" version="3.0" xml:lang="en"> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>ELS-COMMON lib : module "XML" utilities</xd:p> </xd:desc> </xd:doc> <xsl:import href="els-common_constants.xsl"/> <xd:doc>Get the full XML path of any node in an XML with position predicates([n]) cf. http://www.xsltfunctions.com/xsl/functx_path-to-node-with-pos.html </xd:doc> <xsl:template match="*" name="els:get-xpath" mode="get-xpath"> <xsl:param name="node" select="." as="node()"/> <xsl:param name="nsprefix" select="''" as="xs:string"/> <xsl:param name="display_position" select="true()" as="xs:boolean"/> <xsl:variable name="result" as="xs:string*"> <xsl:for-each select="$node/ancestor-or-self::*"> <xsl:variable name="id" select="generate-id(.)" as="xs:string"/> <xsl:variable name="name" select="name()" as="xs:string"/> <xsl:choose> <xsl:when test="not(contains($name,':'))"> <xsl:value-of select="concat('/',if ($nsprefix!='') then (concat($nsprefix,':')) else(''), $name)"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="concat('/', $name)"/> </xsl:otherwise> </xsl:choose> <xsl:for-each select="../*[name() = $name]"> <xsl:if test="generate-id(.)=$id and $display_position"> <!--FIXME : add position() != 1 to get rid of unusfull "[1]" predicates--> <xsl:text>[</xsl:text> <xsl:value-of select="format-number(position(),'0')"/> <xsl:text>]</xsl:text> </xsl:if> </xsl:for-each> </xsl:for-each> <xsl:if test="not($node/self::*)"> <xsl:value-of select="concat('/@',name($node))"/> </xsl:if> </xsl:variable> <xsl:value-of select="string-join($result, '')"/> </xsl:template> <xd:doc> <xd:desc> <xd:p>els:get-xpath return full XML path of the current node</xd:p> <xd:p>If saxon:path() is available then it will be used, else we will use the template "els:get-xpath"</xd:p> </xd:desc> <xd:param name="node">[Node] Node we wan the XML path</xd:param> <xd:return>XML path of $node</xd:return> </xd:doc> <xsl:function name="els:get-xpath" as="xs:string"> <xsl:param name="node" as="node()"/> <xsl:choose> <xsl:when test="function-available('saxon:path')"> <xsl:value-of select="saxon:path($node)" use-when="function-available('saxon:path')"/> <!--To avoid a saxon warning at compilation time, we plan the case (impossible in this when) of the "inverse" use-when (If not, Saxon will warng of a condition brnanch that could return an empty seq instead of a string--> <xsl:value-of select="'This will never happen here'" use-when="not(function-available('saxon:path'))"/> </xsl:when> <xsl:otherwise> <xsl:variable name="xpath" as="xs:string"> <xsl:call-template name="els:get-xpath"> <xsl:with-param name="node" select="$node" as="node()"/> </xsl:call-template> </xsl:variable> <xsl:value-of select="$xpath"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc> <xd:desc> <xd:p>els:get-xpath with more arguments (call for template els:get-xpath instead of saxon:path)</xd:p> </xd:desc> <xd:param name="node">[Node] node to get the XML path</xd:param> <xd:param name="nsprefix">Adding a prefixe on each path item</xd:param> <xd:param name="display_position">Diplay position predicate for each item of the path</xd:param> <xd:return>XML path of the $node formated as indicated with $nsprefix and $display_position</xd:return> </xd:doc> <xsl:function name="els:get-xpath" as="xs:string"> <xsl:param name="node" as="node()"/> <xsl:param name="nsprefix" as="xs:string"/> <xsl:param name="display_position" as="xs:boolean"/> <xsl:variable name="xpath" as="xs:string"> <xsl:call-template name="els:get-xpath"> <xsl:with-param name="node" select="$node" as="node()"/> <xsl:with-param name="nsprefix" select="$nsprefix" as="xs:string"/> <xsl:with-param name="display_position" select="$display_position" as="xs:boolean"/> </xsl:call-template> </xsl:variable> <xsl:value-of select="string-join(tokenize($xpath,'/'),'/')"/> </xsl:function> <!--============================--> <!--PSEUDO ATTRIBUTES--> <!--============================--> <xd:doc> <xd:desc> <xd:p>Generate xml attribute from a string pseudo attributes</xd:p> </xd:desc> <xd:param name="str">Any string with pseudo attributes</xd:param> <xd:param name="attQuot">Quot used in the pattern to recongnize attributes</xd:param> <xd:return>A list of xml attribute, one for each recognized pseudo attribute</xd:return> </xd:doc> <xsl:function name="els:pseudoAttributes2xml" as="attribute()*"> <xsl:param name="str" as="xs:string?"/> <xsl:param name="attQuot" as="xs:string"/> <xsl:if test="normalize-space($str) != ''"> <xsl:analyze-string select="$str" regex="([^\s]*)={$attQuot}(.*?){$attQuot}"> <xsl:matching-substring> <xsl:attribute name="{regex-group(1)}" select="regex-group(2)"/> </xsl:matching-substring> </xsl:analyze-string> <!--FIXME : faut-il dissocier le 1er attribut (sans espace devant) des autres ? <xsl:analyze-string select="$str" regex="^{$attName}={$attQuot}(.*?){$attQuot}"> <xsl:matching-substring> <xsl:value-of select="regex-group(1)"/> </xsl:matching-substring> <xsl:non-matching-substring> <xsl:analyze-string select="." regex="\s+{$attName}={$attQuot}(.*?){$attQuot}"> <xsl:matching-substring> <xsl:value-of select="regex-group(1)"/> </xsl:matching-substring> </xsl:analyze-string> </xsl:non-matching-substring> </xsl:analyze-string>--> </xsl:if> </xsl:function> <!--Default $attQuot is double quot--> <xsl:function name="els:pseudoAttributes2xml" as="attribute()*"> <xsl:param name="str" as="xs:string?"/> <xsl:sequence select="els:pseudoAttributes2xml($str, $els:dquot)"/> </xsl:function> <!--The same function but for only one attribute name. It can return more than one xml attribute in case the string has multiple occurence of the same pseudo attribute--> <xsl:function name="els:pseudoAttribute2xml" as="attribute()*"> <xsl:param name="str" as="xs:string?"/> <xsl:param name="attName" as="xs:string"/> <xsl:param name="attQuot" as="xs:string"/> <xsl:sequence select="els:pseudoAttributes2xml($str, $attQuot)[name(.) = $attName]"/> </xsl:function> <!--Default $attQuot is double quot--> <xsl:function name="els:pseudoAttribute2xml" as="attribute()*"> <xsl:param name="str" as="xs:string?"/> <xsl:param name="attName" as="xs:string"/> <xsl:sequence select="els:pseudoAttribute2xml($str, $attName, $els:dquot)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Get a pseudo attribute value within a string, typicaly a processing-instruction string</xd:p> <xd:p>Exemple : els:getPseudoAttributeValue('<?xml version= "1.0" encoding="UTF-8"?>','encoding')='utf-8'</xd:p> </xd:desc> <xd:param name="str">Any string with pseudo attributes</xd:param> <xd:param name="attName">Name of the attribute</xd:param> <xd:param name="attQuot">Quot type used in the pseudo attribute (" or ')</xd:param> <xd:return>Value of the attribute. If there are multiple attribute with the same name in the string, the it will return several strings of values</xd:return> </xd:doc> <!--FIXME : il existe une fonction saxon qui fait ça (saxon:getPseudoAttribute)--> <xsl:function name="els:getPseudoAttributeValue" as="xs:string*"> <xsl:param name="str" as="xs:string?"/> <xsl:param name="attName" as="xs:string"/> <xsl:param name="attQuot" as="xs:string"/> <xsl:for-each select="els:pseudoAttribute2xml($str, $attName, $attQuot)"> <xsl:value-of select="."/> </xsl:for-each> </xsl:function> <!--Default $attQuot is double quot--> <xsl:function name="els:getPseudoAttributeValue" as="xs:string*"> <xsl:param name="str" as="xs:string?"/> <xsl:param name="attName" as="xs:string"/> <xsl:sequence select="els:getPseudoAttributeValue($str, $attName, $els:dquot)"/> </xsl:function> <!-- Renvoie true/false si une PI contient un attribut donné --> <xsl:function name="els:hasPseudoAttribute" as="xs:boolean"> <xsl:param name="str" as="xs:string?"/> <xsl:param name="attName" as="xs:string"/> <xsl:param name="attQuot" as="xs:string"/> <xsl:sequence select="count(els:pseudoAttribute2xml($str, $attName, $attQuot)) != 0"/> </xsl:function> <!--Default $attQuot is double quot--> <xsl:function name="els:hasPseudoAttribute" as="xs:boolean"> <xsl:param name="str" as="xs:string?"/> <xsl:param name="attName" as="xs:string"/> <xsl:sequence select="els:hasPseudoAttribute($str, $attName, $els:dquot)"/> </xsl:function> <!--==================--> <!--OTHERS XML --> <!--==================--> <xd:doc>Check if a node has a specific ancestor</xd:doc> <xsl:function name="els:hasAncestor" as="xs:boolean"> <xsl:param name="node" as="node()"/> <xsl:param name="ancestor" as="element()"/> <xsl:sequence select="some $anc in $node/ancestor::* satisfies ($anc is $ancestor)"/> </xsl:function> <xd:doc>Check if the element has a specific style</xd:doc> <xsl:function name="els:hasStyle" as="xs:boolean"> <xsl:param name="e" as="element()"/> <xsl:param name="style" as="xs:string"/> <xsl:sequence select="tokenize(normalize-space($e/@style), ';') = normalize-space($style)"/> </xsl:function> <xd:doc>Check if the element has a specific class (several class values might be tested at once)</xd:doc> <xsl:function name="els:hasClass" as="xs:boolean"> <xsl:param name="e" as="element()"/> <xsl:param name="class" as="xs:string*"/> <xsl:sequence select="tokenize($e/@class, '\s+') = $class"/> </xsl:function> <xd:doc>Check if one of the class value of an element matches a specific regex (several class regex might be tested at once)</xd:doc> <xsl:function name="els:hasClassMatchingRegex" as="xs:boolean"> <xsl:param name="e" as="element()"/> <xsl:param name="class.regex" as="xs:string*"/> <xsl:variable name="class.regex.delimited" select="concat('^', $class.regex, '$')" as="xs:string"/> <xsl:sequence select="some $class in tokenize($e/@class, '\s+') satisfies matches($class, $class.regex.delimited)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Add a value in class attribute if this value is not already present</xd:p> <xd:p>Example of use: <xsl:copy> <xsl:copy-of select="@*"/> <!--"except @class" is not necessary here it will be overrided--> <xsl:attribute name="class" select="els:addClass(., 'myClass')"/> <xsl:apply-templates/> </xsl:copy></xd:p> </xd:desc> </xd:doc> <xsl:function name="els:addClass" as="attribute(class)"> <xsl:param name="e" as="element()"/> <xsl:param name="class" as="xs:string"/> <xsl:choose> <!--If the element has already a class value we want to add, do nothing, keep the attribut as is--> <xsl:when test="els:hasClass($e, $class)"> <xsl:attribute name="class" select="$e/@class"/> </xsl:when> <!--Else: make a new class attribute with the original class value and the new class added--> <xsl:otherwise> <xsl:attribute name="class" select="normalize-space(concat($e/@class, ' ', $class))"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc> <xd:desc> <xd:p>Delete one class value in a class attribute of the element</xd:p> </xd:desc> <xd:param name="e">[Element] the element</xd:param> <xd:param name="classToRemove">[String] The class value to be removed</xd:param> <xd:return>[Attribute]The same class attribute with one removed value</xd:return> </xd:doc> <xsl:function name="els:removeOneClass" as="attribute(class)?"> <xsl:param name="e" as="element()"/> <xsl:param name="classToRemove" as="xs:string"/> <xsl:choose> <xsl:when test="els:hasClass($e, $classToRemove)"> <xsl:attribute name="class" select="string-join(tokenize($e/@class, '\s+')[. != $classToRemove], ' ')"/> </xsl:when> <xsl:otherwise> <xsl:copy-of select="$e/@class"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc>Mode to delete indentations</xd:doc> <xsl:template match="text()[matches(.,'\n[ \t]*')]" mode="els:deleteIndentation"> <xsl:value-of select="replace(.,'\n[ \t]*', ' ')"/> </xsl:template> <xsl:template match="node() | @*" mode="els:deleteIndentation"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> <xd:desc>Copy an element and its attributes and "continue" the job in the current mode</xd:desc> <xsl:template name="els:copyAndContinue"> <xsl:copy copy-namespaces="no"> <xsl:copy-of select="@*"/> <xsl:apply-templates select="node()" mode="#current"/> </xsl:copy> </xsl:template> <xd:doc>Generic copy template</xd:doc> <xsl:template match="node() | @*" mode="els:copy"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> <!--A template to deal with namespace declaration at root element--> <!--param namespaces is a sequences of <els:namespace name="xxx" uri="yyy"/>--> <xsl:template match="/*" mode="els:fixNamespaceDeclarations"> <xsl:param name="namespaces" as="element(els:namespace)*"/> <xsl:copy copy-namespaces="no"> <xsl:for-each select="$namespaces"> <xsl:namespace name="{@name}" select="@uri"/> </xsl:for-each> <xsl:apply-templates select="@* | node()" mode="#current"/> </xsl:copy> </xsl:template> <!--copy template--> <xsl:template match="node() | @*" mode="els:fixNamespaceDeclarations" priority="-1"> <xsl:copy copy-namespaces="no"> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> <xd:doc> <xd:desc> <xd:p>Display any node (element, attribute, text, pi, etc.) as a readable string</xd:p> </xd:desc> <xd:param name="node">The node to be displayed</xd:param> <xd:return>A textual representation of <xd:ref name="$node" type="parameter">$node</xd:ref></xd:return> </xd:doc> <xsl:function name="els:displayNode" as="xs:string"> <xsl:param name="node" as="item()"/> <xsl:variable name="tmp" as="xs:string*"> <xsl:choose> <xsl:when test="empty($node)">empty_sequence</xsl:when> <xsl:when test="$node/self::*"> <xsl:text>element():</xsl:text> <xsl:value-of select="name($node)"/> <xsl:if test="$node/@*"> <xsl:text>_</xsl:text> </xsl:if> <xsl:for-each select="$node/@*"> <xsl:sort/> <xsl:value-of select="concat('@',name(),'=',$els:dquot,.,$els:dquot,if (position()!=last()) then ('_') else (''))"/> </xsl:for-each> </xsl:when> <!--FIXME : ce test ne marche pas... ?--> <xsl:when test="$node/self::text()"> <xsl:text>text() </xsl:text> <xsl:value-of select="substring($node,1,30)"/> </xsl:when> <xsl:when test="$node/self::comment()"> <xsl:text>comment() </xsl:text> <xsl:value-of select="substring($node,1,30)"/> </xsl:when> <xsl:when test="$node/self::processing-instruction()"> <xsl:text>processing-instruction() </xsl:text> <xsl:value-of select="substring($node,1,30)"/> </xsl:when> <xsl:when test="$node/self::document-node()"> <xsl:text>document-node() </xsl:text> </xsl:when> <xsl:otherwise> <xsl:text>unrecognized node type</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:value-of select="string-join($tmp,'')"/> </xsl:function> <!-- Application de la fonction saxon:evaluate à un contexte donné, retourne la séquence de noeuds correspondants --> <!-- SSI saxon:eval est disponible --> <!--Cette écriture est pratique pour certains prédicats où les 2 paramètres sont indépendants--> <xd:doc> <xd:desc> <xd:p>Apply saxon:eval to a given context</xd:p> </xd:desc> <xd:param name="xpath">[String] xpath to be evaluated</xd:param> <xd:param name="e">[Element] Context element</xd:param> <xd:return>[item*] result of the evaluation</xd:return> </xd:doc> <xsl:function name="els:evaluate-xpath" as="item()*"> <xsl:param name="xpath" as="xs:string"/> <xsl:param name="e" as="element()"/> <!--<xsl:sequence use-when="function-available('saxon:evaluate')" select="$e/saxon:evaluate($xpath)"/>--> <xsl:sequence use-when="function-available('saxon:eval') and function-available('saxon:expression')" select="$e/saxon:eval(saxon:expression($xpath, $e))"/> <!--The 2nd argument of saxon:expression permit to define the default namespace--> <xsl:message use-when="not(function-available('saxon:eval')) or not(function-available('saxon:expression'))" terminate="yes">[FATAL][els-common.xsl] function els:evaluate-xpath() has crashed because saxon:eval (saxon:expression) in not available. You must be using SAXON EE or PE to run this function</xsl:message> </xsl:function> <xd:doc> <xd:desc> <xd:p>Template to do the same thing as saxon:serialize(node, xsl:output/@name) but: - can take several nodes (usefull for mixed content) - no serialization options, unlike xsl:output</xd:p> </xd:desc> <xd:param name="nodes">[Nodes] any nodes (typicaly mixed content)</xd:param> <xd:param name="copyNS">Determine if we copy namespace declarations on "roots elements" (i.e. elements from <xd:ref name="nodes" type="parameter">$nodes</xd:ref> which have no parent element)</xd:param> <!--<xd:param name="format">Name of an xsl:ouput to get serialization options to apply</xd:param>--> <xd:return>The XML as a string</xd:return> </xd:doc> <xsl:function name="els:serialize" as="xs:string"> <xsl:param name="nodes" as="node()*"/> <xsl:param name="copyNS" as="xs:boolean"/> <!--<xsl:param name="outputName" as="xs:string"/>--> <xsl:variable name="serialize-xml-as-string" as="xs:string*"> <xsl:apply-templates select="$nodes" mode="els:serialize"> <!--<xsl:with-param name="outputName" select="$outputName" tunnel="yes" as="xs:string"/>--> <xsl:with-param name="copyNSOnRootElements" select="$copyNS" tunnel="yes" as="xs:boolean"/> </xsl:apply-templates> </xsl:variable> <xsl:sequence select="string-join($serialize-xml-as-string, '')"/> </xsl:function> <xd:doc>1 argument signature of els:serialize($nodes as node()*, $copyNS as xs:boolean). By default : no copy of the namespace declarations on "roots elements"</xd:doc> <!--TODO : $copyNS est à false() par défaut pour conserver un comportement ISO de la signature à 1 argument de la fonction -> voir pour passer sa valeur à true() si pas d'impact.--> <xsl:function name="els:serialize" as="xs:string"> <xsl:param name="nodes" as="node()*"/> <xsl:sequence select="els:serialize($nodes,false())"/> </xsl:function> <xd:doc>Mode "els:serialize" for elements</xd:doc> <!--TODO : $copyNSOnRootElements conservé avec une valeur par défaut pour rétro-compatibilité (au cas où le template serait appelé en dehors de la fonction).--> <xsl:template match="*" mode="els:serialize"> <xsl:param name="copyNSOnRootElements" tunnel="yes" select="false()" as="xs:boolean"/> <!--fixme : utilisation de saxon:serialize ? oui mais il faut passer le output et je n'y arrive pas--> <!--<xsl:param name="outputName" required="yes" tunnel="yes" as="xs:string"/> <xsl:value-of select="saxon:serialize(., $outputName)"/>--> <xsl:text><</xsl:text> <xsl:value-of select="name()"/> <!-- Copie des déclarations de NS si $copyNSOnRootElements + l'élément n'a pas de parent --> <xsl:if test="$copyNSOnRootElements and not(parent::*)"> <!-- Can't redefine 'xml' prefix (already implicit) --> <xsl:for-each select="namespace::node()[name() != 'xml']"> <xsl:text> xmlns</xsl:text> <xsl:if test="name() != ''"> <xsl:value-of select="concat(':',name())"/> </xsl:if> <xsl:text>="</xsl:text> <xsl:value-of select="."/> <xsl:text>"</xsl:text> </xsl:for-each> </xsl:if> <xsl:for-each select="@*"> <xsl:text> </xsl:text> <xsl:value-of select="name()"/> <xsl:text>="</xsl:text> <xsl:value-of select="."/> <xsl:text>"</xsl:text> </xsl:for-each> <xsl:choose> <!--auto-fermant--> <xsl:when test="empty(node())"> <xsl:text>/></xsl:text> </xsl:when> <!--ou pas--> <xsl:otherwise> <xsl:text>></xsl:text> <xsl:apply-templates mode="#current"/> <xsl:text></</xsl:text> <xsl:value-of select="name()"/> <xsl:text>></xsl:text> </xsl:otherwise> </xsl:choose> </xsl:template> <xd:doc>Mode "els:serialize" for text nodes: spaces are normalized</xd:doc> <xsl:template match="text()" mode="els:serialize"> <xsl:if test="starts-with(.,' ')"> <xsl:text> </xsl:text> </xsl:if> <xsl:value-of select="normalize-space(.)"/> <xsl:if test="ends-with(.,' ')"> <xsl:text> </xsl:text> </xsl:if> </xsl:template> <xd:doc>Mode "els:serialize" for comments</xd:doc> <xsl:template match="comment()" mode="els:serialize"> <xsl:text><!-- </xsl:text> <xsl:value-of select="."/> <xsl:text> --></xsl:text> </xsl:template> <xd:doc>Mode "els:serialize" for PI</xd:doc> <xsl:template match="processing-instruction()" mode="els:serialize"> <xsl:text><?</xsl:text> <xsl:value-of select="name()"/> <xsl:text> </xsl:text> <xsl:value-of select="."/> <xsl:text>?></xsl:text> </xsl:template> <!--===============================--> <!--GROUP and WRAP XML--> <!--===============================--> <xd:doc>3 args signature of els:wrap-elements-adjacent-by-names()</xd:doc> <xsl:function name="els:wrap-elements-adjacent-by-names" as="node()*"> <xsl:param name="context" as="element()"/> <xsl:param name="adjacent.names" as="xs:string+"/> <xsl:param name="wrapper" as="element()"/> <xsl:sequence select="els:wrap-elements-adjacent-by-names($context, $adjacent.names, $wrapper, true())"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Wrap "adjacent by name" elements into a new element "wrapper".</xd:p> <xd:p>CAUTION : any text, pi, comment within context will be loose !</xd:p> </xd:desc> <xd:param name="context">Parent of the adjacents elements to wrap</xd:param> <xd:param name="adjacent.names">sequence of qualified names to set adjacent elements</xd:param> <xd:param name="wrapper">element wrapper</xd:param> <xd:param name="keep-context">Say if the context shoulb be kept or not in the result</xd:param> <xd:return>context (or its content) with wrapped adjacents element</xd:return> </xd:doc> <xsl:function name="els:wrap-elements-adjacent-by-names" as="node()*"> <xsl:param name="context" as="element()"/> <xsl:param name="adjacent.names" as="xs:string+"/> <xsl:param name="wrapper" as="element()"/> <xsl:param name="keep-context" as="xs:boolean"/> <xsl:sequence select="els:wrap-elements-adjacent( $context, function($e) as xs:boolean {name($e) = $adjacent.names}, $wrapper, $keep-context)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Wrap adjacent elements into a new element "wrapper".</xd:p> <xd:p>CAUTION : any text, pi, comment within context will be loose !</xd:p> </xd:desc> <xd:param name="context">Parent of the adjacents elements to wrap</xd:param> <xd:param name="adjacent.function">An Xpath function to set the adjacence condition</xd:param> <xd:param name="wrapper">element wrapper</xd:param> <xd:param name="keep-context">Say if the context shoulb be kept or not in the result</xd:param> <xd:return>context (or its content) with wrapped adjacents element</xd:return> </xd:doc> <xsl:function name="els:wrap-elements-adjacent" as="node()*"> <xsl:param name="context" as="element()"/> <xsl:param name="adjacent.function"/> <!--as="xs:string"--> <xsl:param name="wrapper" as="element()"/> <xsl:param name="keep-context" as="xs:boolean"/> <xsl:variable name="content" as="item()*"> <xsl:for-each-group select="$context/*" group-adjacent="$adjacent.function(.)"> <xsl:variable name="cg" select="current-group()" as="element()*"/> <xsl:choose> <xsl:when test="current-grouping-key()"> <xsl:for-each select="$wrapper"> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:copy-of select="$cg"/> </xsl:copy> </xsl:for-each> </xsl:when> <xsl:otherwise> <xsl:copy-of select="current-group()"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:variable> <xsl:choose> <xsl:when test="$keep-context"> <xsl:for-each select="$context"> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:sequence select="$content"/> </xsl:copy> </xsl:for-each> </xsl:when> <xsl:otherwise> <xsl:sequence select="$content"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc>3 args signature of els:wrap-elements-adjacent-by-names()</xd:doc> <xsl:function name="els:wrap-elements-starting-with-names" as="node()*"> <xsl:param name="context" as="element()"/> <xsl:param name="starts.names" as="xs:string+"/> <xsl:param name="wrapper" as="element()"/> <xsl:sequence select="els:wrap-elements-starting-with-names($context, $starts.names, $wrapper, true())"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Wrap elements starting with specific names into a new element "wrapper" </xd:p> </xd:desc> <xd:param name="context">Parent of the adjacents elements to wrap</xd:param> <xd:param name="starts.names">sequence of names to set starting elements</xd:param> <xd:param name="wrapper">element wrapper</xd:param> <xd:param name="keep-context">Say if the context shoulb be kept or not in the result</xd:param> <xd:return>context (or its content) with wrapped adjacents element</xd:return> </xd:doc> <xsl:function name="els:wrap-elements-starting-with-names" as="node()*"> <xsl:param name="context" as="element()"/> <xsl:param name="starts.names" as="xs:string+"/> <xsl:param name="wrapper" as="element()"/> <xsl:param name="keep-context" as="xs:boolean"/> <xsl:sequence select="els:wrap-elements-starting-with( $context, function($e as element()) as xs:boolean {name($e) = $starts.names}, $wrapper, $keep-context)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Wrap elements starting with specific names into a new element "wrapper" </xd:p> </xd:desc> <xd:param name="context">Parent of the adjacents elements to wrap</xd:param> <xd:param name="starts.function">An Xpath function to set the starting group condition</xd:param> <xd:param name="wrapper">element wrapper</xd:param> <xd:param name="keep-context">Say if the context shoulb be kept or not in the result</xd:param> <xd:return>context (or its content) with wrapped adjacents element</xd:return> </xd:doc> <xsl:function name="els:wrap-elements-starting-with" as="element()*"> <xsl:param name="context" as="element()"/> <xsl:param name="starts.function"/> <!--as="xs:string"--> <xsl:param name="wrapper" as="element()"/> <xsl:param name="keep-context" as="xs:boolean"/> <xsl:variable name="content" as="item()*"> <xsl:for-each-group select="$context/node()" group-starting-with="*[$starts.function(.)]"> <xsl:variable name="cg" select="current-group()" as="node()*"/> <xsl:for-each select="$wrapper"> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:copy-of select="$cg"/> </xsl:copy> </xsl:for-each> </xsl:for-each-group> </xsl:variable> <xsl:choose> <xsl:when test="$keep-context"> <xsl:for-each select="$context"> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:sequence select="$content"/> </xsl:copy> </xsl:for-each> </xsl:when> <xsl:otherwise> <xsl:sequence select="$content"/> </xsl:otherwise> </xsl:choose> </xsl:function> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:functx="http://www.functx.com" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" exclude-result-prefixes="#all" version="3.0" xml:lang="en"> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>ELS-COMMON lib : module "FILES" utilities</xd:p> </xd:desc> </xd:doc> <xsl:import href="functx.xsl"/> <xd:doc> <xd:desc> <xd:p>Return the file name from an abolute or a relativ path</xd:p> <xd:p>If <xd:ref name="filePath" type="parameter">$filePath</xd:ref> is empty it will retunr an empty string (not an empty sequence)</xd:p> </xd:desc> <xd:param name="filePath">[String] path of the file (typically string(base-uri())</xd:param> <xd:param name="withExt">[Boolean] with or without extension</xd:param> <xd:return>File name (with or without extension)</xd:return> </xd:doc> <xsl:function name="els:getFileName" as="xs:string"> <xsl:param name="filePath" as="xs:string?"/> <xsl:param name="withExt" as="xs:boolean"/> <xsl:choose> <!-- An empty string would lead an error in the next when (because of a empty regex)--> <xsl:when test="normalize-space($filePath) = ''"> <xsl:value-of select="$filePath"/> </xsl:when> <xsl:otherwise> <xsl:variable name="fileNameWithExt" select="functx:substring-after-last-match($filePath,'/')" as="xs:string?"/> <xsl:variable name="fileNameNoExt" select="functx:substring-before-last-match($fileNameWithExt,'\.')" as="xs:string?"/> <!-- If the fileName has no extension (ex. : "foo"), els:getFileExt() will return renvoie the file name... which is not what expected <xsl:variable name="ext" select="concat('.',els:getFileExt($fileNameWithExt))" as="xs:string"/>--> <!-- This works with no extension files -> $ext is an empty string here--> <xsl:variable name="ext" select="functx:substring-after-match($fileNameWithExt,$fileNameNoExt)" as="xs:string?"/> <xsl:sequence select="concat('', $fileNameNoExt, if ($withExt) then ($ext) else (''))"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc>1arg signature of els:getFileName. Default : extension is on</xd:doc> <xsl:function name="els:getFileName" as="xs:string"> <xsl:param name="filePath" as="xs:string?"/> <xsl:sequence select="els:getFileName($filePath,true())"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Get the extension of a file from it an absolute or relativ path</xd:p> <xd:p>If <xd:ref name="filePath" type="parameter">$filePath</xd:ref> is empty, it will return an empty string (not an empty sequence)</xd:p> </xd:desc> <xd:param name="filePath">[String] path of the file (typically string(base-uri())</xd:param> <xd:return>The file extension if it has one</xd:return> </xd:doc> <xsl:function name="els:getFileExt" as="xs:string?"> <xsl:param name="filePath" as="xs:string?"/> <xsl:choose> <xsl:when test="not(matches(functx:substring-after-last-match($filePath,'/'), '\.'))"> <!-- To return an empty string (not an empty sequence) --> <xsl:text/> </xsl:when> <xsl:otherwise> <xsl:sequence select="concat('',functx:substring-after-last-match($filePath,'\.'))"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc> <xd:desc> <xd:p>Get the folder path of a file path, level can be specified to have the parg</xd:p> </xd:desc> <xd:param name="filePath">File path as xs:string (use string(base-uri()) if necessary)</xd:param> <xd:param name="level">Tree level as integer, min = 1 (1 = full path, 2 = full path except last folder, etc.)</xd:param> <xd:return>Folder Path as string</xd:return> </xd:doc> <xsl:function name="els:getFolderPath" as="xs:string"> <xsl:param name="filePath" as="xs:string?"/> <xsl:param name="level" as="xs:integer"/> <xsl:variable name="level.normalized" as="xs:integer" select="if ($level ge 1) then ($level) else (1)"/> <xsl:value-of select="string-join(tokenize($filePath,'/')[position() le (last() - $level.normalized)],'/')"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>1 arg Signature of els:getFolderPath(). Default is to get the full folder path to the file (level = 1)</xd:p> </xd:desc> <xd:param name="filePath">File path as xs:string (use string(base-uri()) if necessary)</xd:param> <xd:return>Full folder path of the file path</xd:return> </xd:doc> <xsl:function name="els:getFolderPath" as="xs:string"> <xsl:param name="filePath" as="xs:string?"/> <xsl:sequence select="els:getFolderPath($filePath,1)"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Get the folder name of a file path</xd:p> </xd:desc> <xd:param name="filePath">File path as xs:string (use string(base-uri()) if necessary)</xd:param> <xd:param name="level">Tree level as integer, min = 1 (1 = parent folder of the file, 2 = "grand-parent-folderName", etc.)</xd:param> <xd:return>The folder name of the nth parent folder of file</xd:return> </xd:doc> <xsl:function name="els:getFolderName" as="xs:string"> <xsl:param name="filePath" as="xs:string?"/> <xsl:param name="level" as="xs:integer"/> <xsl:variable name="level.normalized" as="xs:integer" select="if ($level ge 1) then ($level) else (1)"/> <xsl:value-of select="tokenize($filePath,'/')[last() - $level.normalized]"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>1 arg signature of els:getFolderName()</xd:p> </xd:desc> <xd:param name="filePath">File path as xs:string (use string(base-uri()) if necessary)</xd:param> <xd:return>Name of the parent folder of the file</xd:return> </xd:doc> <xsl:function name="els:getFolderName" as="xs:string"> <xsl:param name="filePath" as="xs:string?"/> <xsl:value-of select="els:getFolderName($filePath,1)"/> </xsl:function> <!--=========================--> <!--RelativeURI--> <!--=========================--> <!--Adapted from https://github.com/cmarchand/xsl-doc/blob/master/src/main/xsl/lib/common.xsl--> <!--FIXME : should parameters be cast as xs:anyUri ??--> <xd:doc> <xd:desc> <xd:p>Returns the relative path from a source folder to a target file.</xd:p> <xd:p>Both source.folder and target.file must be absolute URI</xd:p> <xd:p>If there is no way to walk a relative path from the source folder to the target file, then absolute target file URI is returned</xd:p> </xd:desc> <xd:param name="source.folder">The source folder URI</xd:param> <xd:param name="target.file">The target file URI</xd:param> <xd:return>The relative path to walk from source.folder to target.file</xd:return> </xd:doc> <xsl:function name="els:getRelativePath" as="xs:string"> <xsl:param name="source.folder" as="xs:string"/> <xsl:param name="target.file" as="xs:string"/> <xsl:choose> <xsl:when test="normalize-space($source.folder) eq ''"> <xsl:message>[ERROR][els:getRelativePath] $source.folder must not be an empty string</xsl:message> <xsl:sequence select="($target.file, '')[1]"/> </xsl:when> <xsl:when test="normalize-space($target.file) eq ''"> <xsl:message>[ERROR][els:getRelativePath] $target.file must not be an empty string</xsl:message> <xsl:sequence select="($target.file, '')[1]"/> </xsl:when> <xsl:when test="els:isAbsoluteUri($source.folder)"> <xsl:choose> <xsl:when test="not(els:isAbsoluteUri($target.file))"><xsl:sequence select="string-join((tokenize($source.folder,'/'),tokenize($target.file,'/')),'/')"/></xsl:when> <xsl:otherwise> <!-- If protocols are differents : return $target --> <xsl:variable name="protocol" select="els:getUriProtocol($source.folder)" as="xs:string"/> <xsl:choose> <xsl:when test="$protocol eq els:getUriProtocol($target.file)"> <!-- How many identical items are there at the beginning of each uri ?--> <xsl:variable name="sourceSeq" select="tokenize(substring(els:normalizeFilePath($source.folder),string-length($protocol) +1),'/')" as="xs:string*"/> <xsl:variable name="targetSeq" select="tokenize(substring(els:normalizeFilePath($target.file),string-length($protocol) +1),'/')" as="xs:string*"/> <xsl:variable name="nbCommonElements" as="xs:integer" select="els:getNbEqualsItems($sourceSeq, $targetSeq)"/> <xsl:variable name="goUpLevels" as="xs:integer" select="count($sourceSeq) - $nbCommonElements"/> <xsl:variable name="goUp" as="xs:string*" select="(for $i in (1 to $goUpLevels) return '..')"/> <xsl:sequence select="string-join(($goUp, subsequence($targetSeq, $nbCommonElements+1)),'/')"/> </xsl:when> <xsl:otherwise><xsl:sequence select="$target.file"/></xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:when> <xsl:otherwise> <xsl:variable name="absoluteSource" as="xs:string" select="xs:string(resolve-uri($source.folder))"/> <xsl:choose> <xsl:when test="els:isAbsoluteUri($absoluteSource)"> <xsl:sequence select="els:getRelativePath($absoluteSource, $target.file)"/> </xsl:when> <xsl:otherwise> <xsl:message>[ERROR][els:getRelativePath] $source.folder="<xsl:value-of select="$source.folder"/>" can not be resolved as an absolute URI</xsl:message> <xsl:sequence select="($target.file, '')[1]"/> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc> <xd:desc>Normalize the URI path. I.E. removes any /./ and folder/.. moves</xd:desc> <xd:param name="path">The path to normalize</xd:param> <xd:return>The normalized path, as a <tt>xs:string</tt></xd:return> </xd:doc> <xsl:function name="els:normalizeFilePath" as="xs:string"> <xsl:param name="path" as="xs:string"/> <xsl:sequence select="els:removeLeadingDotSlash(els:removeSingleDot(els:removeDoubleDot($path)))"/> </xsl:function> <xd:doc> <xd:desc>Removes single dot in path URI. . are always a self reference, so ./ can always be removed safely</xd:desc> <xd:param name="path">The path to remove single dots from</xd:param> <xd:return>The clean path, as xs:string</xd:return> </xd:doc> <xsl:function name="els:removeSingleDot" as="xs:string"> <xsl:param name="path" as="xs:string"/> <xsl:variable name="temp" select="replace($path, '/\./','/')" as="xs:string"/> <xsl:choose> <xsl:when test="matches($temp, '/\./')"> <xsl:sequence select="els:removeSingleDot($temp)"/> </xsl:when> <xsl:otherwise><xsl:sequence select="$temp"/></xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc> <xd:desc>Removes the leading "./" from the path</xd:desc> <xd:param name="path">The path to clean</xd:param> <xd:return>The clean path</xd:return> </xd:doc> <xsl:function name="els:removeLeadingDotSlash" as="xs:string"> <xsl:param name="path" as="xs:string"/> <xsl:variable name="temp" select="replace($path, '^\./','')" as="xs:string"/> <xsl:choose> <xsl:when test="starts-with($temp, './')"> <xsl:sequence select="els:removeLeadingDotSlash($temp)"/> </xsl:when> <xsl:otherwise><xsl:sequence select="$temp"/></xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc> <xd:desc>Removes .. in an URI when it is preceded by a folder reference. So, removes /xxxx/.. </xd:desc> <xd:param name="path">The path to clean</xd:param> <xd:return>The clean path</xd:return> </xd:doc> <xsl:function name="els:removeDoubleDot" as="xs:string"> <xsl:param name="path" as="xs:string"/> <xsl:variable name="temp" as="xs:string" select="replace($path,'/[^./]*/\.\./','/')"/> <xsl:choose> <xsl:when test="matches($temp,'/[^./]*/\.\./')"> <xsl:sequence select="els:removeDoubleDot($temp)"/> </xsl:when> <xsl:otherwise><xsl:sequence select="$temp"/></xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc> <xd:desc>Returns true if the provided URI is absolute, false otherwise</xd:desc> <xd:param name="path">The URI to test</xd:param> <xd:return><tt>true</tt> if the URI is absolute</xd:return> </xd:doc> <xsl:function name="els:isAbsoluteUri" as="xs:boolean"> <xsl:param name="path" as="xs:string"/> <xsl:choose> <xsl:when test="$path eq ''"> <xsl:sequence select="false()"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="matches($path,'[a-zA-Z0-9]+:.*')"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc> <xd:desc>Returns the protocol of an URI</xd:desc> <xd:param name="path">The URI to check</xd:param> <xd:return>The protocol of the URI</xd:return> </xd:doc> <xsl:function name="els:getUriProtocol" as="xs:string"> <xsl:param name="path" as="xs:string"/> <xsl:variable name="protocol" select="substring-before($path,':')" as="xs:string"/> <xsl:choose> <xsl:when test="string-length($protocol) gt 0"><xsl:sequence select="$protocol"/></xsl:when> <xsl:otherwise><xsl:message>[ERROR][els:protocol] $path="<xsl:value-of select="$path"/>" must be an absolute URI</xsl:message></xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc> <xd:desc>Compare pair to pair seq1 and seq2 items, and returns the numbers of deeply-equals items</xd:desc> <xd:param name="seq1">The first sequence</xd:param> <xd:param name="seq2">The second sequence</xd:param> </xd:doc> <xsl:function name="els:getNbEqualsItems" as="xs:integer"> <xsl:param name="seq1" as="item()*"/> <xsl:param name="seq2" as="item()*"/> <xsl:choose> <xsl:when test="deep-equal($seq1[1],$seq2[1])"> <xsl:sequence select="els:getNbEqualsItems(els:tail($seq1), els:tail($seq2))+1"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="0"/> </xsl:otherwise> </xsl:choose> </xsl:function> <!--FIXME : utiliser la fonction tail native en xpath3.0 (https://www.w3.org/TR/xpath-functions-30/#func-tail)--> <xsl:function name="els:tail" as="item()*"> <xsl:param name="seq" as="item()*"/> <xsl:sequence select="subsequence($seq, 2)"/> </xsl:function> </xsl:stylesheet>
<!-- cf. http://www.xsltfunctions.com/xsl/functx-1.0-doc-2007-01.xsl ADAPTATION ELS : Suppression de xmlns:local="http://www.datypic.com/local" à la racine Inutile et peut créer des conflits --><!-- ******************************** The FunctX XSLT Function Library ******************************** Copyright (C) 2007 Datypic This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA For more information on the FunctX XSLT library, contact contrib@functx.com. @version 1.0 @see http://www.xsltfunctions.com --><xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dxmlf="http://www.datypic.com/xmlf" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:functx="http://www.functx.com" exclude-result-prefixes="dxmlf xs" version="3.0"> <!-- Adds attributes to XML elements @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_add-attributes.html @param $elements the element(s) to which you wish to add the attribute @param $attrNames the name(s) of the attribute(s) to add @param $attrValues the value(s) of the attribute(s) to add --> <xsl:function name="functx:add-attributes" as="element()?"> <xsl:param name="elements" as="element()*"/> <xsl:param name="attrNames" as="xs:QName*"/> <xsl:param name="attrValues" as="xs:anyAtomicType*"/> <xsl:for-each select="$elements"> <xsl:variable name="element" select="."/> <xsl:copy> <xsl:for-each select="$attrNames"> <xsl:variable name="seq" select="position()"/> <xsl:if test="not($element/@*[node-name(.) = current()])"> <xsl:attribute name="{.}" namespace="{namespace-uri-from-QName(.)}" select="$attrValues[$seq]"/> </xsl:if> </xsl:for-each> <xsl:copy-of select="@*|node()"/> </xsl:copy> </xsl:for-each> </xsl:function> <!-- Adds months to a date @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_add-months.html @param $date the date @param $months the number of months to add --> <xsl:function name="functx:add-months" as="xs:date?"> <xsl:param name="date" as="xs:anyAtomicType?"/> <xsl:param name="months" as="xs:integer"/> <xsl:sequence select=" xs:date($date) + functx:yearMonthDuration(0,$months) "/> </xsl:function> <!-- Adds attributes to XML elements @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_add-or-update-attributes.html @param $elements the element(s) to which you wish to add the attribute @param $attrNames the name(s) of the attribute(s) to add @param $attrValues the value(s) of the attribute(s) to add --> <xsl:function name="functx:add-or-update-attributes" as="element()?"> <xsl:param name="elements" as="element()*"/> <xsl:param name="attrNames" as="xs:QName*"/> <xsl:param name="attrValues" as="xs:anyAtomicType*"/> <xsl:for-each select="$elements"> <xsl:copy> <xsl:for-each select="$attrNames"> <xsl:variable name="seq" select="position()"/> <xsl:attribute name="{.}" namespace="{namespace-uri-from-QName(.)}" select="$attrValues[$seq]"/> </xsl:for-each> <xsl:copy-of select="@*[not(node-name(.) = $attrNames)]|node()"/> </xsl:copy> </xsl:for-each> </xsl:function> <!-- Whether a value is all whitespace or a zero-length string @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_all-whitespace.html @param $arg the string (or node) to test --> <xsl:function name="functx:all-whitespace" as="xs:boolean"> <xsl:param name="arg" as="xs:string?"/> <xsl:sequence select=" normalize-space($arg) = '' "/> </xsl:function> <!-- Whether all the values in a sequence are distinct @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_are-distinct-values.html @param $seq the sequence of values --> <xsl:function name="functx:are-distinct-values" as="xs:boolean"> <xsl:param name="seq" as="xs:anyAtomicType*"/> <xsl:sequence select=" count(distinct-values($seq)) = count($seq) "/> </xsl:function> <!-- The built-in type of an atomic value @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_atomic-type.html @param $values the value(s) whose type you want to determine --> <xsl:function name="functx:atomic-type" as="xs:string*"> <xsl:param name="values" as="xs:anyAtomicType*"/> <xsl:sequence select=" for $val in $values return (if ($val instance of xs:untypedAtomic) then 'xs:untypedAtomic' else if ($val instance of xs:anyURI) then 'xs:anyURI' else if ($val instance of xs:string) then 'xs:string' else if ($val instance of xs:QName) then 'xs:QName' else if ($val instance of xs:boolean) then 'xs:boolean' else if ($val instance of xs:base64Binary) then 'xs:base64Binary' else if ($val instance of xs:hexBinary) then 'xs:hexBinary' else if ($val instance of xs:integer) then 'xs:integer' else if ($val instance of xs:decimal) then 'xs:decimal' else if ($val instance of xs:float) then 'xs:float' else if ($val instance of xs:double) then 'xs:double' else if ($val instance of xs:date) then 'xs:date' else if ($val instance of xs:time) then 'xs:time' else if ($val instance of xs:dateTime) then 'xs:dateTime' else if ($val instance of xs:dayTimeDuration) then 'xs:dayTimeDuration' else if ($val instance of xs:yearMonthDuration) then 'xs:yearMonthDuration' else if ($val instance of xs:duration) then 'xs:duration' else if ($val instance of xs:gMonth) then 'xs:gMonth' else if ($val instance of xs:gYear) then 'xs:gYear' else if ($val instance of xs:gYearMonth) then 'xs:gYearMonth' else if ($val instance of xs:gDay) then 'xs:gDay' else if ($val instance of xs:gMonthDay) then 'xs:gMonthDay' else 'unknown') "/> </xsl:function> <!-- The average, counting "empty" values as zero @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_avg-empty-is-zero.html @param $values the values to be averaged @param $allNodes the sequence of all nodes to find the average over --> <xsl:function name="functx:avg-empty-is-zero" as="xs:double"> <xsl:param name="values" as="xs:anyAtomicType*"/> <xsl:param name="allNodes" as="node()*"/> <xsl:sequence select=" if (empty($allNodes)) then 0 else sum($values[string(.) != '']) div count($allNodes) "/> </xsl:function> <!-- Whether a value is between two provided values @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_between-exclusive.html @param $value the value to be tested @param $minValue the minimum value @param $maxValue the maximum value --> <xsl:function name="functx:between-exclusive" as="xs:boolean"> <xsl:param name="value" as="xs:anyAtomicType?"/> <xsl:param name="minValue" as="xs:anyAtomicType"/> <xsl:param name="maxValue" as="xs:anyAtomicType"/> <xsl:sequence select=" $value > $minValue and $value < $maxValue "/> </xsl:function> <!-- Whether a value is between two provided values, or equal to one of them @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_between-inclusive.html @param $value the value to be tested @param $minValue the minimum value @param $maxValue the maximum value --> <xsl:function name="functx:between-inclusive" as="xs:boolean"> <xsl:param name="value" as="xs:anyAtomicType?"/> <xsl:param name="minValue" as="xs:anyAtomicType"/> <xsl:param name="maxValue" as="xs:anyAtomicType"/> <xsl:sequence select=" $value >= $minValue and $value <= $maxValue "/> </xsl:function> <!-- Turns a camelCase string into space-separated words @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_camel-case-to-words.html @param $arg the string to modify @param $delim the delimiter for the words (e.g. a space) --> <xsl:function name="functx:camel-case-to-words" as="xs:string"> <xsl:param name="arg" as="xs:string?"/> <xsl:param name="delim" as="xs:string"/> <xsl:sequence select=" concat(substring($arg,1,1), replace(substring($arg,2),'(\p{Lu})', concat($delim, '$1'))) "/> </xsl:function> <!-- Capitalizes the first character of a string @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_capitalize-first.html @param $arg the word or phrase to capitalize --> <xsl:function name="functx:capitalize-first" as="xs:string?"> <xsl:param name="arg" as="xs:string?"/> <xsl:sequence select=" concat(upper-case(substring($arg,1,1)), substring($arg,2)) "/> </xsl:function> <!-- Changes the names of elements in an XML fragment @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_change-element-names-deep.html @param $nodes the element(s) to change @param $oldNames the sequence of names to change from @param $newNames the sequence of names to change to --> <xsl:function name="functx:change-element-names-deep" as="node()*"> <xsl:param name="nodes" as="node()*"/> <xsl:param name="oldNames" as="xs:QName*"/> <xsl:param name="newNames" as="xs:QName*"/> <xsl:if test="count($oldNames) != count($newNames)"> <xsl:sequence select="error( xs:QName('functx:Different_number_of_names'))"/> </xsl:if> <xsl:for-each select="$nodes"> <xsl:variable name="node" select="."/> <xsl:choose> <xsl:when test="$node instance of element()"> <xsl:variable name="theName" select="functx:if-empty ($newNames[index-of($oldNames, node-name($node))], node-name($node))"/> <xsl:element name="{$theName}" namespace="{namespace-uri-from-QName($theName)}"> <xsl:sequence select="($node/@*, functx:change-element-names-deep($node/node(), $oldNames, $newNames))"/> </xsl:element> </xsl:when> <xsl:when test="$node instance of document-node()"> <xsl:document> <xsl:sequence select="functx:change-element-names-deep( $node/node(), $oldNames, $newNames)"/> </xsl:document> </xsl:when> <xsl:otherwise> <xsl:sequence select="$node"/> </xsl:otherwise> </xsl:choose> </xsl:for-each> </xsl:function> <!-- Changes the namespace of XML elements and its descendants @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_change-element-ns-deep.html @param $nodes the nodes to change @param $newns the new namespace @param $prefix the prefix to use for the new namespace --> <xsl:function name="functx:change-element-ns-deep" as="node()*"> <xsl:param name="nodes" as="node()*"/> <xsl:param name="newns" as="xs:string"/> <xsl:param name="prefix" as="xs:string"/> <xsl:for-each select="$nodes"> <xsl:variable name="node" select="."/> <xsl:choose> <xsl:when test="$node instance of element()"> <xsl:element name="{concat($prefix, if ($prefix = '') then '' else ':', local-name($node))}" namespace="{$newns}"> <xsl:sequence select="($node/@*, functx:change-element-ns-deep($node/node(), $newns, $prefix))"/> </xsl:element> </xsl:when> <xsl:when test="$node instance of document-node()"> <xsl:document> <xsl:sequence select="functx:change-element-ns-deep( $node/node(), $newns, $prefix)"/> </xsl:document> </xsl:when> <xsl:otherwise> <xsl:sequence select="$node"/> </xsl:otherwise> </xsl:choose> </xsl:for-each> </xsl:function> <!-- Changes the namespace of XML elements @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_change-element-ns.html @param $elements the elements to change @param $newns the new namespace @param $prefix the prefix to use for the new namespace --> <xsl:function name="functx:change-element-ns" as="element()?"> <xsl:param name="elements" as="element()*"/> <xsl:param name="newns" as="xs:string"/> <xsl:param name="prefix" as="xs:string"/> <xsl:for-each select="$elements"> <xsl:variable name="element" select="."/> <xsl:element name="{concat($prefix, if ($prefix = '') then '' else ':', local-name($element))}" namespace="{$newns}"> <xsl:sequence select="$element/@*, $element/node()"/> </xsl:element> </xsl:for-each> </xsl:function> <!-- Converts a string to a sequence of characters @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_chars.html @param $arg the string to split --> <xsl:function name="functx:chars" as="xs:string*"> <xsl:param name="arg" as="xs:string?"/> <xsl:sequence select=" for $ch in string-to-codepoints($arg) return codepoints-to-string($ch) "/> </xsl:function> <!-- Whether a string contains any of a sequence of strings @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_contains-any-of.html @param $arg the string to test @param $searchStrings the strings to look for --> <xsl:function name="functx:contains-any-of" as="xs:boolean"> <xsl:param name="arg" as="xs:string?"/> <xsl:param name="searchStrings" as="xs:string*"/> <xsl:sequence select=" some $searchString in $searchStrings satisfies contains($arg,$searchString) "/> </xsl:function> <!-- Whether one string contains another, without regard to case @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_contains-case-insensitive.html @param $arg the string to search @param $substring the substring to find --> <xsl:function name="functx:contains-case-insensitive" as="xs:boolean?"> <xsl:param name="arg" as="xs:string?"/> <xsl:param name="substring" as="xs:string"/> <xsl:sequence select=" contains(upper-case($arg), upper-case($substring)) "/> </xsl:function> <!-- Whether one string contains another, as a separate word @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_contains-word.html @param $arg the string to search @param $word the word to find --> <xsl:function name="functx:contains-word" as="xs:boolean"> <xsl:param name="arg" as="xs:string?"/> <xsl:param name="word" as="xs:string"/> <xsl:sequence select=" matches(upper-case($arg), concat('^(.*\W)?', upper-case(functx:escape-for-regex($word)), '(\W.*)?$')) "/> </xsl:function> <!-- Copies attributes from one element to another @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_copy-attributes.html @param $copyTo the element to copy attributes to @param $copyFrom the element to copy attributes from --> <xsl:function name="functx:copy-attributes" as="element()"> <xsl:param name="copyTo" as="element()"/> <xsl:param name="copyFrom" as="element()"/> <xsl:element name="{node-name($copyTo)}"> <xsl:sequence select=" ($copyTo/@*[not(node-name(.) = $copyFrom/@*/node-name(.))], $copyFrom/@*, $copyTo/node())"/> </xsl:element> </xsl:function> <!-- Construct a date from a year, month and day @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_date.html @param $year the year @param $month the month @param $day the day --> <xsl:function name="functx:date" as="xs:date"> <xsl:param name="year" as="xs:anyAtomicType"/> <xsl:param name="month" as="xs:anyAtomicType"/> <xsl:param name="day" as="xs:anyAtomicType"/> <xsl:sequence select=" xs:date( concat( functx:pad-integer-to-length(xs:integer($year),4),'-', functx:pad-integer-to-length(xs:integer($month),2),'-', functx:pad-integer-to-length(xs:integer($day),2))) "/> </xsl:function> <!-- Construct a date/time from individual components @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_datetime.html @param $year the year @param $month the month @param $day the day @param $hour the hour @param $minute the minute @param $second the second --> <xsl:function name="functx:dateTime" as="xs:dateTime"> <xsl:param name="year" as="xs:anyAtomicType"/> <xsl:param name="month" as="xs:anyAtomicType"/> <xsl:param name="day" as="xs:anyAtomicType"/> <xsl:param name="hour" as="xs:anyAtomicType"/> <xsl:param name="minute" as="xs:anyAtomicType"/> <xsl:param name="second" as="xs:anyAtomicType"/> <xsl:sequence select=" xs:dateTime( concat(functx:date($year,$month,$day),'T', functx:time($hour,$minute,$second))) "/> </xsl:function> <!-- The day of the year (a number between 1 and 366) @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_day-in-year.html @param $date the date --> <xsl:function name="functx:day-in-year" as="xs:integer?"> <xsl:param name="date" as="xs:anyAtomicType?"/> <xsl:sequence select=" days-from-duration( xs:date($date) - functx:first-day-of-year($date)) + 1 "/> </xsl:function> <!-- The abbreviated day of the week, from a date, in English @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_day-of-week-abbrev-en.html @param $date the date --> <xsl:function name="functx:day-of-week-abbrev-en" as="xs:string?"> <xsl:param name="date" as="xs:anyAtomicType?"/> <xsl:sequence select=" ('Sun', 'Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat') [functx:day-of-week($date) + 1] "/> </xsl:function> <!-- The name of the day of the week, from a date, in English @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_day-of-week-name-en.html @param $date the date --> <xsl:function name="functx:day-of-week-name-en" as="xs:string?"> <xsl:param name="date" as="xs:anyAtomicType?"/> <xsl:sequence select=" ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday') [functx:day-of-week($date) + 1] "/> </xsl:function> <!-- The day of the week, from a date @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_day-of-week.html @param $date the date --> <xsl:function name="functx:day-of-week" as="xs:integer?"> <xsl:param name="date" as="xs:anyAtomicType?"/> <xsl:sequence select=" if (empty($date)) then () else xs:integer((xs:date($date) - xs:date('1901-01-06')) div xs:dayTimeDuration('P1D')) mod 7 "/> </xsl:function> <!-- Construct a dayTimeDuration from a number of days, hours, etc. @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_daytimeduration.html @param $days the number of days @param $hours the number of hours @param $minutes the number of minutes @param $seconds the number of seconds --> <xsl:function name="functx:dayTimeDuration" as="xs:dayTimeDuration"> <xsl:param name="days" as="xs:decimal?"/> <xsl:param name="hours" as="xs:decimal?"/> <xsl:param name="minutes" as="xs:decimal?"/> <xsl:param name="seconds" as="xs:decimal?"/> <xsl:sequence select=" (xs:dayTimeDuration('P1D') * functx:if-empty($days,0)) + (xs:dayTimeDuration('PT1H') * functx:if-empty($hours,0)) + (xs:dayTimeDuration('PT1M') * functx:if-empty($minutes,0)) + (xs:dayTimeDuration('PT1S') * functx:if-empty($seconds,0)) "/> </xsl:function> <!-- Number of days in the month @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_days-in-month.html @param $date the date --> <xsl:function name="functx:days-in-month" as="xs:integer?"> <xsl:param name="date" as="xs:anyAtomicType?"/> <xsl:sequence select=" if (month-from-date(xs:date($date)) = 2 and functx:is-leap-year($date)) then 29 else (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) [month-from-date(xs:date($date))] "/> </xsl:function> <!-- The depth (level) of a node in an XML tree @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_depth-of-node.html @param $node the node to check --> <xsl:function name="functx:depth-of-node" as="xs:integer"> <xsl:param name="node" as="node()?"/> <xsl:sequence select=" count($node/ancestor-or-self::node()) "/> </xsl:function> <!-- The distinct names of all attributes in an XML fragment @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_distinct-attribute-names.html @param $nodes the root to start from --> <xsl:function name="functx:distinct-attribute-names" as="xs:string*"> <xsl:param name="nodes" as="node()*"/> <xsl:sequence select=" distinct-values($nodes//@*/name(.)) "/> </xsl:function> <!-- The XML nodes with distinct values, taking into account attributes and descendants @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_distinct-deep.html @param $nodes the sequence of nodes to test --> <xsl:function name="functx:distinct-deep" as="node()*"> <xsl:param name="nodes" as="node()*"/> <xsl:sequence select=" for $seq in (1 to count($nodes)) return $nodes[$seq][not(functx:is-node-in-sequence-deep-equal( .,$nodes[position() < $seq]))] "/> </xsl:function> <!-- The distinct names of all elements in an XML fragment @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_distinct-element-names.html @param $nodes the root(s) to start from --> <xsl:function name="functx:distinct-element-names" as="xs:string*"> <xsl:param name="nodes" as="node()*"/> <xsl:sequence select=" distinct-values($nodes/descendant-or-self::*/name(.)) "/> </xsl:function> <!-- The distinct paths of all descendant elements in an XML fragment @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_distinct-element-paths.html @param $nodes the root(s) to start from --> <xsl:function name="functx:distinct-element-paths" as="xs:string*"> <xsl:param name="nodes" as="node()*"/> <xsl:sequence select=" distinct-values(functx:path-to-node($nodes/descendant-or-self::*)) "/> </xsl:function> <!-- The distinct XML nodes in a sequence (by node identity) @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_distinct-nodes.html @param $nodes the node sequence --> <xsl:function name="functx:distinct-nodes" as="node()*"> <xsl:param name="nodes" as="node()*"/> <xsl:sequence select=" for $seq in (1 to count($nodes)) return $nodes[$seq][not(functx:is-node-in-sequence( .,$nodes[position() < $seq]))] "/> </xsl:function> <!-- Converts a timezone like "-05:00" or "Z" into xs:dayTimeDuration @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_duration-from-timezone.html @param $timezone the time zone, in (+|-)HH:MM format --> <xsl:function name="functx:duration-from-timezone" as="xs:dayTimeDuration"> <xsl:param name="timezone" as="xs:string"/> <xsl:sequence select=" xs:dayTimeDuration( if (not(matches($timezone,'Z|[\+\-]\d{2}:\d{2}'))) then error(xs:QName('functx:Invalid_Timezone_Value')) else if ($timezone = 'Z') then 'PT0S' else replace($timezone,'\+?(\d{2}):\d{2}','PT$1H') ) "/> </xsl:function> <!-- Dynamically evaluates a simple XPath path @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_dynamic-path.html @param $parent the root to start from @param $path the path expression --> <xsl:function name="functx:dynamic-path" as="item()*"> <xsl:param name="parent" as="node()"/> <xsl:param name="path" as="xs:string"/> <xsl:variable name="nextStep" select="functx:substring-before-if-contains($path,'/')"/> <xsl:variable name="restOfSteps" select="substring-after($path,'/')"/> <xsl:for-each select=" ($parent/*[functx:name-test(name(),$nextStep)], $parent/@*[functx:name-test(name(), substring-after($nextStep,'@'))])"> <xsl:variable name="child" select="."/> <xsl:sequence select="if ($restOfSteps) then functx:dynamic-path($child, $restOfSteps) else $child"/> </xsl:for-each> </xsl:function> <!-- Escapes regex special characters @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_escape-for-regex.html @param $arg the string to escape --> <xsl:function name="functx:escape-for-regex" as="xs:string"> <xsl:param name="arg" as="xs:string?"/> <xsl:sequence select=" replace($arg, '(\.|\[|\]|\\|\||\-|\^|\$|\?|\*|\+|\{|\}|\(|\))','\\$1') "/> </xsl:function> <!-- Whether one (and only one) of two boolean values is true @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_exclusive-or.html @param $arg1 the first boolean value @param $arg2 the second boolean value --> <xsl:function name="functx:exclusive-or" as="xs:boolean?"> <xsl:param name="arg1" as="xs:boolean?"/> <xsl:param name="arg2" as="xs:boolean?"/> <xsl:sequence select=" $arg1 != $arg2 "/> </xsl:function> <!-- The first day of the month of a date @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_first-day-of-month.html @param $date the date --> <xsl:function name="functx:first-day-of-month" as="xs:date?"> <xsl:param name="date" as="xs:anyAtomicType?"/> <xsl:sequence select=" functx:date(year-from-date(xs:date($date)), month-from-date(xs:date($date)), 1) "/> </xsl:function> <!-- The first day of the year of a date @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_first-day-of-year.html @param $date the date --> <xsl:function name="functx:first-day-of-year" as="xs:date?"> <xsl:param name="date" as="xs:anyAtomicType?"/> <xsl:sequence select=" functx:date(year-from-date(xs:date($date)), 1, 1) "/> </xsl:function> <!-- The XML node in a sequence that appears first in document order @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_first-node.html @param $nodes the sequence of nodes --> <xsl:function name="functx:first-node" as="node()?"> <xsl:param name="nodes" as="node()*"/> <xsl:sequence select=" ($nodes/.)[1] "/> </xsl:function> <!-- Whether an XML node follows another without being its descendant @author W3C XML Query Working Group @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_follows-not-descendant.html @param $a the first node @param $b the second node --> <xsl:function name="functx:follows-not-descendant" as="xs:boolean"> <xsl:param name="a" as="node()?"/> <xsl:param name="b" as="node()?"/> <xsl:sequence select=" $a >> $b and empty($b intersect $a/ancestor::node()) "/> </xsl:function> <!-- Moves title words like "the" and "a" to the end of strings @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_format-as-title-en.html @param $titles the titles to format --> <xsl:function name="functx:format-as-title-en" as="xs:string*"> <xsl:param name="titles" as="xs:string*"/> <xsl:variable name="wordsToMoveToEnd" select="('A', 'An', 'The')"/> <xsl:for-each select="$titles"> <xsl:variable name="title" select="."/> <xsl:variable name="firstWord" select="functx:substring-before-match($title,'\W')"/> <xsl:sequence select="if ($firstWord = $wordsToMoveToEnd) then replace($title,'(.*?)\W(.*)', '$2, $1') else $title"/> </xsl:for-each> </xsl:function> <!-- Returns the fragment from a URI @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_fragment-from-uri.html @param $uri the URI --> <xsl:function name="functx:fragment-from-uri" as="xs:string?"> <xsl:param name="uri" as="xs:string?"/> <xsl:sequence select=" substring-after($uri,'#') "/> </xsl:function> <!-- Whether an element has element-only content @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_has-element-only-content.html @param $element the XML element to test --> <xsl:function name="functx:has-element-only-content" as="xs:boolean"> <xsl:param name="element" as="element()"/> <xsl:sequence select=" not($element/text()[normalize-space(.) != '']) and $element/* "/> </xsl:function> <!-- Whether an element has empty content @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_has-empty-content.html @param $element the XML element to test --> <xsl:function name="functx:has-empty-content" as="xs:boolean"> <xsl:param name="element" as="element()"/> <xsl:sequence select=" not($element/node()) "/> </xsl:function> <!-- Whether an element has mixed content @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_has-mixed-content.html @param $element the XML element to test --> <xsl:function name="functx:has-mixed-content" as="xs:boolean"> <xsl:param name="element" as="element()"/> <xsl:sequence select=" $element/text()[normalize-space(.) != ''] and $element/* "/> </xsl:function> <!-- Whether an element has simple content @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_has-simple-content.html @param $element the XML element to test --> <xsl:function name="functx:has-simple-content" as="xs:boolean"> <xsl:param name="element" as="element()"/> <xsl:sequence select=" $element/text() and not($element/*) "/> </xsl:function> <!-- Gets the ID of an XML element @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_id-from-element.html @param $element the element --> <xsl:function name="functx:id-from-element" as="xs:string?"> <xsl:param name="element" as="element()?"/> <xsl:sequence select=" data(($element/@*[id(.) is ..])[1]) "/> </xsl:function> <!-- Gets XML element(s) that have an attribute with a particular value @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_id-untyped.html @param $node the root node(s) to start from @param $id the "id" to find --> <xsl:function name="functx:id-untyped" as="element()*"> <xsl:param name="node" as="node()*"/> <xsl:param name="id" as="xs:anyAtomicType"/> <xsl:sequence select=" $node//*[@* = $id] "/> </xsl:function> <!-- The first argument if it is not empty, otherwise the second argument @author W3C XML Query WG @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_if-absent.html @param $arg the item(s) that may be absent @param $value the item(s) to use if the item is absent --> <xsl:function name="functx:if-absent" as="item()*"> <xsl:param name="arg" as="item()*"/> <xsl:param name="value" as="item()*"/> <xsl:sequence select=" if (exists($arg)) then $arg else $value "/> </xsl:function> <!-- The first argument if it is not blank, otherwise the second argument @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_if-empty.html @param $arg the node that may be empty @param $value the item(s) to use if the node is empty --> <xsl:function name="functx:if-empty" as="item()*"> <xsl:param name="arg" as="item()?"/> <xsl:param name="value" as="item()*"/> <xsl:sequence select=" if (string($arg) != '') then data($arg) else $value "/> </xsl:function> <!-- The position of a node in a sequence, based on contents and attributes @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_index-of-deep-equal-node.html @param $nodes the node sequence @param $nodeToFind the node to find in the sequence --> <xsl:function name="functx:index-of-deep-equal-node" as="xs:integer*"> <xsl:param name="nodes" as="node()*"/> <xsl:param name="nodeToFind" as="node()"/> <xsl:sequence select=" for $seq in (1 to count($nodes)) return $seq[deep-equal($nodes[$seq],$nodeToFind)] "/> </xsl:function> <!-- The first position of a matching substring @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_index-of-match-first.html @param $arg the string @param $pattern the pattern to match --> <xsl:function name="functx:index-of-match-first" as="xs:integer?"> <xsl:param name="arg" as="xs:string?"/> <xsl:param name="pattern" as="xs:string"/> <xsl:sequence select=" if (matches($arg,$pattern)) then string-length(tokenize($arg, $pattern)[1]) + 1 else () "/> </xsl:function> <!-- The position of a node in a sequence, based on node identity @author W3C XML Query Working Group @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_index-of-node.html @param $nodes the node sequence @param $nodeToFind the node to find in the sequence --> <xsl:function name="functx:index-of-node" as="xs:integer*"> <xsl:param name="nodes" as="node()*"/> <xsl:param name="nodeToFind" as="node()"/> <xsl:sequence select=" for $seq in (1 to count($nodes)) return $seq[$nodes[$seq] is $nodeToFind] "/> </xsl:function> <!-- The first position of a substring @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_index-of-string-first.html @param $arg the string @param $substring the substring to find --> <xsl:function name="functx:index-of-string-first" as="xs:integer?"> <xsl:param name="arg" as="xs:string?"/> <xsl:param name="substring" as="xs:string"/> <xsl:sequence select=" if (contains($arg, $substring)) then string-length(substring-before($arg, $substring))+1 else () "/> </xsl:function> <!-- The last position of a substring @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_index-of-string-last.html @param $arg the string @param $substring the substring to find --> <xsl:function name="functx:index-of-string-last" as="xs:integer?"> <xsl:param name="arg" as="xs:string?"/> <xsl:param name="substring" as="xs:string"/> <xsl:sequence select=" functx:index-of-string($arg, $substring)[last()] "/> </xsl:function> <!-- The position(s) of a substring @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_index-of-string.html @param $arg the string @param $substring the substring to find --> <xsl:function name="functx:index-of-string" as="xs:integer*"> <xsl:param name="arg" as="xs:string?"/> <xsl:param name="substring" as="xs:string"/> <xsl:sequence select=" if (contains($arg, $substring)) then (string-length(substring-before($arg, $substring))+1, for $other in functx:index-of-string(substring-after($arg, $substring), $substring) return $other + string-length(substring-before($arg, $substring)) + string-length($substring)) else () "/> </xsl:function> <!-- Inserts a string at a specified position @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_insert-string.html @param $originalString the original string to insert into @param $stringToInsert the string to insert @param $pos the position --> <xsl:function name="functx:insert-string" as="xs:string"> <xsl:param name="originalString" as="xs:string?"/> <xsl:param name="stringToInsert" as="xs:string?"/> <xsl:param name="pos" as="xs:integer"/> <xsl:sequence select=" concat(substring($originalString,1,$pos - 1), $stringToInsert, substring($originalString,$pos)) "/> </xsl:function> <!-- Whether a value is numeric @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_is-a-number.html @param $value the value to test --> <xsl:function name="functx:is-a-number" as="xs:boolean"> <xsl:param name="value" as="xs:anyAtomicType?"/> <xsl:sequence select=" string(number($value)) != 'NaN' "/> </xsl:function> <!-- Whether a URI is absolute @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_is-absolute-uri.html @param $uri the URI to test --> <xsl:function name="functx:is-absolute-uri" as="xs:boolean"> <xsl:param name="uri" as="xs:string?"/> <xsl:sequence select=" matches($uri,'^[a-z]+:') "/> </xsl:function> <!-- Whether an XML node is an ancestor of another node @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_is-ancestor.html @param $node1 the first node @param $node2 the second node --> <xsl:function name="functx:is-ancestor" as="xs:boolean"> <xsl:param name="node1" as="node()"/> <xsl:param name="node2" as="node()"/> <xsl:sequence select=" exists($node1 intersect $node2/ancestor::node()) "/> </xsl:function> <!-- Whether an XML node is a descendant of another node @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_is-descendant.html @param $node1 the first node @param $node2 the second node --> <xsl:function name="functx:is-descendant" as="xs:boolean"> <xsl:param name="node1" as="node()"/> <xsl:param name="node2" as="node()"/> <xsl:sequence select=" boolean($node2 intersect $node1/ancestor::node()) "/> </xsl:function> <!-- Whether a date falls in a leap year @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_is-leap-year.html @param $date the date or year --> <xsl:function name="functx:is-leap-year" as="xs:boolean"> <xsl:param name="date" as="xs:anyAtomicType?"/> <xsl:sequence select=" for $year in xs:integer(substring(string($date),1,4)) return ($year mod 4 = 0 and $year mod 100 != 0) or $year mod 400 = 0 "/> </xsl:function> <!-- Whether an XML node is among the descendants of a sequence, based on contents and attributes @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_is-node-among-descendants-deep-equal.html @param $node the node to test @param $seq the sequence of nodes to search --> <xsl:function name="functx:is-node-among-descendants-deep-equal" as="xs:boolean"> <xsl:param name="node" as="node()?"/> <xsl:param name="seq" as="node()*"/> <xsl:sequence select=" some $nodeInSeq in $seq/descendant-or-self::*/(.|@*) satisfies deep-equal($nodeInSeq,$node) "/> </xsl:function> <!-- Whether an XML node is among the descendants of a sequence, based on node identity @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_is-node-among-descendants.html @param $node the node to test @param $seq the sequence of nodes to search --> <xsl:function name="functx:is-node-among-descendants" as="xs:boolean"> <xsl:param name="node" as="node()?"/> <xsl:param name="seq" as="node()*"/> <xsl:sequence select=" some $nodeInSeq in $seq/descendant-or-self::*/(.|@*) satisfies $nodeInSeq is $node "/> </xsl:function> <!-- Whether an XML node is in a sequence, based on contents and attributes @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_is-node-in-sequence-deep-equal.html @param $node the node to test @param $seq the sequence of nodes to search --> <xsl:function name="functx:is-node-in-sequence-deep-equal" as="xs:boolean"> <xsl:param name="node" as="node()?"/> <xsl:param name="seq" as="node()*"/> <xsl:sequence select=" some $nodeInSeq in $seq satisfies deep-equal($nodeInSeq,$node) "/> </xsl:function> <!-- Whether an XML node is in a sequence, based on node identity @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_is-node-in-sequence.html @param $node the node to test @param $seq the sequence of nodes to search --> <xsl:function name="functx:is-node-in-sequence" as="xs:boolean"> <xsl:param name="node" as="node()?"/> <xsl:param name="seq" as="node()*"/> <xsl:sequence select=" some $nodeInSeq in $seq satisfies $nodeInSeq is $node "/> </xsl:function> <!-- Whether an atomic value appears in a sequence @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_is-value-in-sequence.html @param $value the atomic value to test @param $seq the sequence of values to search --> <xsl:function name="functx:is-value-in-sequence" as="xs:boolean"> <xsl:param name="value" as="xs:anyAtomicType?"/> <xsl:param name="seq" as="xs:anyAtomicType*"/> <xsl:sequence select=" $value = $seq "/> </xsl:function> <!-- The last day of the month of a date @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_last-day-of-month.html @param $date the date --> <xsl:function name="functx:last-day-of-month" as="xs:date?"> <xsl:param name="date" as="xs:anyAtomicType?"/> <xsl:sequence select=" functx:date(year-from-date(xs:date($date)), month-from-date(xs:date($date)), functx:days-in-month($date)) "/> </xsl:function> <!-- The last day of the month of a date @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_last-day-of-year.html @param $date the date --> <xsl:function name="functx:last-day-of-year" as="xs:date?"> <xsl:param name="date" as="xs:anyAtomicType?"/> <xsl:sequence select=" functx:date(year-from-date(xs:date($date)), 12, 31) "/> </xsl:function> <!-- The XML node in a sequence that is last in document order @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_last-node.html @param $nodes the sequence of nodes --> <xsl:function name="functx:last-node" as="node()?"> <xsl:param name="nodes" as="node()*"/> <xsl:sequence select=" ($nodes/.)[last()] "/> </xsl:function> <!-- All XML elements that don't have any child elements @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_leaf-elements.html @param $root the root --> <xsl:function name="functx:leaf-elements" as="element()*"> <xsl:param name="root" as="node()?"/> <xsl:sequence select=" $root/descendant-or-self::*[not(*)] "/> </xsl:function> <!-- Trims leading whitespace @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_left-trim.html @param $arg the string to trim --> <xsl:function name="functx:left-trim" as="xs:string"> <xsl:param name="arg" as="xs:string?"/> <xsl:sequence select=" replace($arg,'^\s+','') "/> </xsl:function> <!-- The number of lines @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_line-count.html @param $arg the string to test --> <xsl:function name="functx:line-count" as="xs:integer"> <xsl:param name="arg" as="xs:string?"/> <xsl:sequence select=" count(functx:lines($arg)) "/> </xsl:function> <!-- Split a string into separate lines @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_lines.html @param $arg the string to split --> <xsl:function name="functx:lines" as="xs:string*"> <xsl:param name="arg" as="xs:string?"/> <xsl:sequence select=" tokenize($arg, '(\r\n?|\n\r?)') "/> </xsl:function> <!-- The maximum depth of elements in an XML tree @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_max-depth.html @param $root the root to start from --> <xsl:function name="functx:max-depth" as="xs:integer?"> <xsl:param name="root" as="node()?"/> <xsl:sequence select=" if ($root/*) then max($root/*/functx:max-depth(.)) + 1 else 1 "/> </xsl:function> <!-- The maximum value in a sequence, figuring out its type (numeric or string) @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_max-determine-type.html @param $seq the sequence of values to test --> <xsl:function name="functx:max-determine-type" as="xs:anyAtomicType?"> <xsl:param name="seq" as="xs:anyAtomicType*"/> <xsl:sequence select=" if (every $value in $seq satisfies ($value castable as xs:double)) then max(for $value in $seq return xs:double($value)) else max(for $value in $seq return xs:string($value)) "/> </xsl:function> <!-- The maximum line length @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_max-line-length.html @param $arg the string to test --> <xsl:function name="functx:max-line-length" as="xs:integer"> <xsl:param name="arg" as="xs:string?"/> <xsl:sequence select=" max( for $line in functx:lines($arg) return string-length($line)) "/> </xsl:function> <!-- The XML node whose typed value is the maximum @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_max-node.html @param $nodes the sequence of nodes to test --> <xsl:function name="functx:max-node" as="node()*"> <xsl:param name="nodes" as="node()*"/> <xsl:sequence select=" $nodes[. = max($nodes)] "/> </xsl:function> <!-- The maximum of a sequence of values, treating them like strings @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_max-string.html @param $strings the sequence of values --> <xsl:function name="functx:max-string" as="xs:string?"> <xsl:param name="strings" as="xs:anyAtomicType*"/> <xsl:sequence select=" max(for $string in $strings return string($string)) "/> </xsl:function> <!-- The minimum value in a sequence, figuring out its type (numeric or string) @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_min-determine-type.html @param $seq the sequence of values to test --> <xsl:function name="functx:min-determine-type" as="xs:anyAtomicType?"> <xsl:param name="seq" as="xs:anyAtomicType*"/> <xsl:sequence select=" if (every $value in $seq satisfies ($value castable as xs:double)) then min(for $value in $seq return xs:double($value)) else min(for $value in $seq return xs:string($value)) "/> </xsl:function> <!-- The XML node whose typed value is the minimum @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_min-node.html @param $nodes the sequence of nodes to test --> <xsl:function name="functx:min-node" as="node()*"> <xsl:param name="nodes" as="node()*"/> <xsl:sequence select=" $nodes[. = min($nodes)] "/> </xsl:function> <!-- The minimum of a sequence of strings, ignoring "empty" values @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_min-non-empty-string.html @param $strings the sequence of strings to search --> <xsl:function name="functx:min-non-empty-string" as="xs:string?"> <xsl:param name="strings" as="xs:string*"/> <xsl:sequence select=" min($strings[. != '']) "/> </xsl:function> <!-- The minimum of a sequence of values, treating them like strings @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_min-string.html @param $strings the sequence of strings --> <xsl:function name="functx:min-string" as="xs:string?"> <xsl:param name="strings" as="xs:anyAtomicType*"/> <xsl:sequence select=" min(for $string in $strings return string($string)) "/> </xsl:function> <!-- Converts a string with format MMDDYYYY (with any delimiters) to a date @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_mmddyyyy-to-date.html @param $dateString the MMDDYYYY string --> <xsl:function name="functx:mmddyyyy-to-date" as="xs:date?"> <xsl:param name="dateString" as="xs:string?"/> <xsl:sequence select=" if (empty($dateString)) then () else if (not(matches($dateString, '^\D*(\d{2})\D*(\d{2})\D*(\d{4})\D*$'))) then error(xs:QName('functx:Invalid_Date_Format')) else xs:date(replace($dateString, '^\D*(\d{2})\D*(\d{2})\D*(\d{4})\D*$', '$3-$1-$2')) "/> </xsl:function> <!-- The month of a date as an abbreviated word (Jan, Feb, etc.) @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_month-abbrev-en.html @param $date the date --> <xsl:function name="functx:month-abbrev-en" as="xs:string?"> <xsl:param name="date" as="xs:anyAtomicType?"/> <xsl:sequence select=" ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec') [month-from-date(xs:date($date))] "/> </xsl:function> <!-- The month of a date as a word (January, February, etc.) @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_month-name-en.html @param $date the date --> <xsl:function name="functx:month-name-en" as="xs:string?"> <xsl:param name="date" as="xs:anyAtomicType?"/> <xsl:sequence select=" ('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December') [month-from-date(xs:date($date))] "/> </xsl:function> <!-- Whether a name matches a list of names or name wildcards @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_name-test.html @param $testname the name to test @param $names the list of names or name wildcards --> <xsl:function name="functx:name-test" as="xs:boolean"> <xsl:param name="testname" as="xs:string?"/> <xsl:param name="names" as="xs:string*"/> <xsl:sequence select=" $testname = $names or $names = '*' or functx:substring-after-if-contains($testname,':') = (for $name in $names return substring-after($name,'*:')) or substring-before($testname,':') = (for $name in $names[contains(.,':*')] return substring-before($name,':*')) "/> </xsl:function> <!-- A list of namespaces used in element/attribute names in an XML fragment @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_namespaces-in-use.html @param $root the root node to start from --> <xsl:function name="functx:namespaces-in-use" as="xs:anyURI*"> <xsl:param name="root" as="node()?"/> <xsl:sequence select=" distinct-values( $root/descendant-or-self::*/(.|@*)/namespace-uri(.)) "/> </xsl:function> <!-- The next day @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_next-day.html @param $date the date --> <xsl:function name="functx:next-day" as="xs:date?"> <xsl:param name="date" as="xs:anyAtomicType?"/> <xsl:sequence select=" xs:date($date) + xs:dayTimeDuration('P1D') "/> </xsl:function> <!-- The XML node kind (element, attribute, text, etc.) @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_node-kind.html @param $nodes the node(s) whose kind you want to determine --> <xsl:function name="functx:node-kind" as="xs:string*"> <xsl:param name="nodes" as="node()*"/> <xsl:sequence select=" for $node in $nodes return if ($node instance of element()) then 'element' else if ($node instance of attribute()) then 'attribute' else if ($node instance of text()) then 'text' else if ($node instance of document-node()) then 'document-node' else if ($node instance of comment()) then 'comment' else if ($node instance of processing-instruction()) then 'processing-instruction' else 'unknown' "/> </xsl:function> <!-- Returns any values that appear more than once in a sequence @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_non-distinct-values.html @param $seq the sequence of values --> <xsl:function name="functx:non-distinct-values" as="xs:anyAtomicType*"> <xsl:param name="seq" as="xs:anyAtomicType*"/> <xsl:sequence select=" for $val in distinct-values($seq) return $val[count($seq[. = $val]) > 1] "/> </xsl:function> <!-- The number of regions that match a pattern @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_number-of-matches.html @param $arg the string to test @param $pattern the regular expression --> <xsl:function name="functx:number-of-matches" as="xs:integer"> <xsl:param name="arg" as="xs:string?"/> <xsl:param name="pattern" as="xs:string"/> <xsl:sequence select=" count(tokenize($arg,$pattern)) - 1 "/> </xsl:function> <!-- Resolves a relative URI and references it, returning an XML document @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_open-ref-document.html @param $refNode a node whose value is a relative URI reference --> <xsl:function name="functx:open-ref-document" as="document-node()"> <xsl:param name="refNode" as="node()"/> <xsl:sequence select=" if (base-uri($refNode)) then doc(resolve-uri($refNode, base-uri($refNode))) else doc(resolve-uri($refNode)) "/> </xsl:function> <!-- Reformats a number as an ordinal number, e.g. 1st, 2nd, 3rd. @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_ordinal-number-en.html @param $num the number --> <xsl:function name="functx:ordinal-number-en" as="xs:string"> <xsl:param name="num" as="xs:integer?"/> <xsl:sequence select=" concat(xs:string($num), if (matches(xs:string($num),'[04-9]$|1[1-3]$')) then 'th' else if (ends-with(xs:string($num),'1')) then 'st' else if (ends-with(xs:string($num),'2')) then 'nd' else if (ends-with(xs:string($num),'3')) then 'rd' else '') "/> </xsl:function> <!-- Pads an integer to a desired length by adding leading zeros @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_pad-integer-to-length.html @param $integerToPad the integer to pad @param $length the desired length --> <xsl:function name="functx:pad-integer-to-length" as="xs:string"> <xsl:param name="integerToPad" as="xs:anyAtomicType?"/> <xsl:param name="length" as="xs:integer"/> <xsl:sequence select=" if ($length < string-length(string($integerToPad))) then error(xs:QName('functx:Integer_Longer_Than_Length')) else concat (functx:repeat-string( '0',$length - string-length(string($integerToPad))), string($integerToPad)) "/> </xsl:function> <!-- Pads a string to a desired length @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_pad-string-to-length.html @param $stringToPad the string to pad @param $padChar the character(s) to use as padding @param $length the desired length --> <xsl:function name="functx:pad-string-to-length" as="xs:string"> <xsl:param name="stringToPad" as="xs:string?"/> <xsl:param name="padChar" as="xs:string"/> <xsl:param name="length" as="xs:integer"/> <xsl:sequence select=" substring( string-join ( ($stringToPad, for $i in (1 to $length) return $padChar) ,'') ,1,$length) "/> </xsl:function> <!-- A unique path to an XML node (or sequence of nodes) @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_path-to-node-with-pos.html @param $node the node sequence --> <xsl:function name="functx:path-to-node-with-pos" as="xs:string"> <xsl:param name="node" as="node()?"/> <xsl:variable name="names" as="xs:string*"> <xsl:for-each select="$node/ancestor-or-self::*"> <xsl:variable name="ancestor" select="."/> <xsl:variable name="sibsOfSameName" select="$ancestor/../*[name() = name($ancestor)]"/> <xsl:sequence select="concat(name($ancestor), if (count($sibsOfSameName) <= 1) then '' else concat( '[',functx:index-of-node($sibsOfSameName,$ancestor),']'))"/> </xsl:for-each> </xsl:variable> <xsl:sequence select="string-join($names,'/')"/> </xsl:function> <!-- A path to an XML node (or sequence of nodes) @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_path-to-node.html @param $nodes the node sequence --> <xsl:function name="functx:path-to-node" as="xs:string*"> <xsl:param name="nodes" as="node()*"/> <xsl:sequence select=" $nodes/string-join(ancestor-or-self::*/name(.), '/') "/> </xsl:function> <!-- Whether an XML node precedes another without being its ancestor @author W3C XML Query Working Group @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_precedes-not-ancestor.html @param $a the first node @param $b the second node --> <xsl:function name="functx:precedes-not-ancestor" as="xs:boolean"> <xsl:param name="a" as="node()?"/> <xsl:param name="b" as="node()?"/> <xsl:sequence select=" $a << $b and empty($a intersect $b/ancestor::node()) "/> </xsl:function> <!-- The previous day @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_previous-day.html @param $date the date --> <xsl:function name="functx:previous-day" as="xs:date?"> <xsl:param name="date" as="xs:anyAtomicType?"/> <xsl:sequence select=" xs:date($date) - xs:dayTimeDuration('P1D') "/> </xsl:function> <!-- Removes attributes from an XML fragment, based on name @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_remove-attributes-deep.html @param $nodes the root(s) to start from @param $names the names of the attributes to remove, or * for all attributes --> <xsl:function name="functx:remove-attributes-deep" as="node()*"> <xsl:param name="nodes" as="node()*"/> <xsl:param name="names" as="xs:string*"/> <xsl:for-each select="$nodes"> <xsl:choose> <xsl:when test=". instance of element()"> <xsl:element name="{node-name(.)}"> <xsl:sequence select=" (@*[not(functx:name-test(name(),$names))], functx:remove-attributes-deep(node(), $names))"/> </xsl:element> </xsl:when> <xsl:when test=". instance of document-node()"> <xsl:document> <xsl:sequence select=" functx:remove-attributes-deep(node(), $names)"/> </xsl:document> </xsl:when> <xsl:otherwise> <xsl:sequence select="."/> </xsl:otherwise> </xsl:choose> </xsl:for-each> </xsl:function> <!-- Removes attributes from an XML element, based on name @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_remove-attributes.html @param $elements the element(s) from which to remove the attributes @param $names the names of the attributes to remove, or * for all attributes --> <xsl:function name="functx:remove-attributes" as="element()"> <xsl:param name="elements" as="element()*"/> <xsl:param name="names" as="xs:string*"/> <xsl:for-each select="$elements"> <xsl:element name="{node-name(.)}"> <xsl:sequence select="(@*[not(functx:name-test(name(),$names))], node())"/> </xsl:element> </xsl:for-each> </xsl:function> <!-- Removes descendant elements from an XML node, based on name @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_remove-elements-deep.html @param $nodes root(s) to start from @param $names the names of the elements to remove --> <xsl:function name="functx:remove-elements-deep" as="node()*"> <xsl:param name="nodes" as="node()*"/> <xsl:param name="names" as="xs:string*"/> <xsl:for-each select="$nodes"> <xsl:choose> <xsl:when test=". instance of element()"> <xsl:if test="not(functx:name-test(name(),$names))"> <xsl:element name="{node-name(.)}"> <xsl:sequence select="@*, functx:remove-elements-deep(node(), $names)"/> </xsl:element> </xsl:if> </xsl:when> <xsl:when test=". instance of document-node()"> <xsl:document> <xsl:sequence select=" functx:remove-elements-deep(node(), $names)"/> </xsl:document> </xsl:when> <xsl:otherwise> <xsl:sequence select="."/> </xsl:otherwise> </xsl:choose> </xsl:for-each> </xsl:function> <!-- Removes descendant XML elements but keeps their content @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_remove-elements-not-contents.html @param $nodes the root(s) to start from @param $names the names of the elements to remove --> <xsl:function name="functx:remove-elements-not-contents" as="node()*"> <xsl:param name="nodes" as="node()*"/> <xsl:param name="names" as="xs:string*"/> <xsl:for-each select="$nodes"> <xsl:choose> <xsl:when test=". instance of element()"> <xsl:choose> <xsl:when test="functx:name-test(name(),$names)"> <xsl:sequence select=" functx:remove-elements-not-contents(node(), $names)"/> </xsl:when> <xsl:otherwise> <xsl:element name="{node-name(.)}"> <xsl:sequence select="@*, functx:remove-elements-not-contents(node(),$names)"/> </xsl:element> </xsl:otherwise> </xsl:choose> </xsl:when> <xsl:when test=". instance of document-node()"> <xsl:document> <xsl:sequence select=" functx:remove-elements-not-contents(node(), $names)"/> </xsl:document> </xsl:when> <xsl:otherwise> <xsl:sequence select="."/> </xsl:otherwise> </xsl:choose> </xsl:for-each> </xsl:function> <!-- Removes child elements from an XML node, based on name @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_remove-elements.html @param $elements the element(s) from which you wish to remove the children @param $names the names of the child elements to remove --> <xsl:function name="functx:remove-elements" as="element()*"> <xsl:param name="elements" as="element()*"/> <xsl:param name="names" as="xs:string*"/> <xsl:for-each select="$elements"> <xsl:element name="{node-name(.)}"> <xsl:sequence select="(@*, node()[not(functx:name-test(name(),$names))])"/> </xsl:element> </xsl:for-each> </xsl:function> <!-- Repeats a string a given number of times @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_repeat-string.html @param $stringToRepeat the string to repeat @param $count the desired number of copies --> <xsl:function name="functx:repeat-string" as="xs:string"> <xsl:param name="stringToRepeat" as="xs:string?"/> <xsl:param name="count" as="xs:integer"/> <xsl:sequence select=" string-join((for $i in 1 to $count return $stringToRepeat), '') "/> </xsl:function> <!-- Replaces the beginning of a string, up to a matched pattern @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_replace-beginning.html @param $arg the entire string to change @param $pattern the pattern of characters to replace up to @param $replacement the replacement string --> <xsl:function name="functx:replace-beginning" as="xs:string"> <xsl:param name="arg" as="xs:string?"/> <xsl:param name="pattern" as="xs:string"/> <xsl:param name="replacement" as="xs:string"/> <xsl:sequence select=" replace($arg, concat('^.*?', $pattern), $replacement) "/> </xsl:function> <!-- Updates the content of one or more elements @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_replace-element-values.html @param $elements the elements whose content you wish to replace @param $values the replacement values --> <xsl:function name="functx:replace-element-values" as="element()*"> <xsl:param name="elements" as="element()*"/> <xsl:param name="values" as="xs:anyAtomicType*"/> <xsl:for-each select="$elements"> <xsl:variable name="seq" select="position()"/> <xsl:element name="{node-name(.)}"> <xsl:sequence select="@*, $values[$seq]"/> </xsl:element> </xsl:for-each> </xsl:function> <!-- Replaces the first match of a pattern @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_replace-first.html @param $arg the entire string to change @param $pattern the pattern of characters to replace @param $replacement the replacement string --> <xsl:function name="functx:replace-first" as="xs:string"> <xsl:param name="arg" as="xs:string?"/> <xsl:param name="pattern" as="xs:string"/> <xsl:param name="replacement" as="xs:string"/> <xsl:sequence select=" replace($arg, concat('(^.*?)', $pattern), concat('$1',$replacement)) "/> </xsl:function> <!-- Performs multiple replacements, using pairs of replace parameters @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_replace-multi.html @param $arg the string to manipulate @param $changeFrom the sequence of strings or patterns to change from @param $changeTo the sequence of strings to change to --> <xsl:function name="functx:replace-multi" as="xs:string?"> <xsl:param name="arg" as="xs:string?"/> <xsl:param name="changeFrom" as="xs:string*"/> <xsl:param name="changeTo" as="xs:string*"/> <xsl:sequence select=" if (count($changeFrom) > 0) then functx:replace-multi( replace($arg, $changeFrom[1], functx:if-absent($changeTo[1],'')), $changeFrom[position() > 1], $changeTo[position() > 1]) else $arg "/> </xsl:function> <!-- Reverses the order of characters @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_reverse-string.html @param $arg the string to reverse --> <xsl:function name="functx:reverse-string" as="xs:string"> <xsl:param name="arg" as="xs:string?"/> <xsl:sequence select=" codepoints-to-string(reverse(string-to-codepoints($arg))) "/> </xsl:function> <!-- Trims trailing whitespace @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_right-trim.html @param $arg the string to trim --> <xsl:function name="functx:right-trim" as="xs:string"> <xsl:param name="arg" as="xs:string?"/> <xsl:sequence select=" replace($arg,'\s+$','') "/> </xsl:function> <!-- Returns the scheme from a URI @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_scheme-from-uri.html @param $uri the URI --> <xsl:function name="functx:scheme-from-uri" as="xs:string?"> <xsl:param name="uri" as="xs:string?"/> <xsl:sequence select=" substring-before($uri,':') "/> </xsl:function> <!-- Whether two sequences have the same XML node content and/or values @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_sequence-deep-equal.html @param $seq1 the first sequence @param $seq2 the second sequence --> <xsl:function name="functx:sequence-deep-equal" as="xs:boolean"> <xsl:param name="seq1" as="item()*"/> <xsl:param name="seq2" as="item()*"/> <xsl:sequence select=" every $i in 1 to max((count($seq1),count($seq2))) satisfies deep-equal($seq1[$i],$seq2[$i]) "/> </xsl:function> <!-- Whether two sequences contain the same XML nodes, regardless of order @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_sequence-node-equal-any-order.html @param $seq1 the first sequence of nodes @param $seq2 the second sequence of nodes --> <xsl:function name="functx:sequence-node-equal-any-order" as="xs:boolean"> <xsl:param name="seq1" as="node()*"/> <xsl:param name="seq2" as="node()*"/> <xsl:sequence select=" not( ($seq1 except $seq2, $seq2 except $seq1)) "/> </xsl:function> <!-- Whether two sequences contain the same XML nodes, in the same order @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_sequence-node-equal.html @param $seq1 the first sequence of nodes @param $seq2 the second sequence of nodes --> <xsl:function name="functx:sequence-node-equal" as="xs:boolean"> <xsl:param name="seq1" as="node()*"/> <xsl:param name="seq2" as="node()*"/> <xsl:sequence select=" every $i in 1 to max((count($seq1),count($seq2))) satisfies $seq1[$i] is $seq2[$i] "/> </xsl:function> <!-- The sequence type that represents a sequence of nodes or values @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_sequence-type.html @param $items the items whose sequence type you want to determine --> <xsl:function name="functx:sequence-type" as="xs:string"> <xsl:param name="items" as="item()*"/> <xsl:sequence select=" concat( if (empty($items)) then 'empty-sequence()' else if (every $val in $items satisfies $val instance of xs:anyAtomicType) then if (count(distinct-values(functx:atomic-type($items))) > 1) then 'xs:anyAtomicType' else functx:atomic-type($items[1]) else if (some $val in $items satisfies $val instance of xs:anyAtomicType) then 'item()' else if (count(distinct-values(functx:node-kind($items))) > 1) then 'node()' else concat(functx:node-kind($items[1]),'()') , if (count($items) > 1) then '+' else '') "/> </xsl:function> <!-- The siblings of an XML element that have the same name @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_siblings-same-name.html @param $element the node --> <xsl:function name="functx:siblings-same-name" as="element()*"> <xsl:param name="element" as="element()?"/> <xsl:sequence select=" $element/../*[node-name(.) = node-name($element)] except $element "/> </xsl:function> <!-- The siblings of an XML node @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_siblings.html @param $node the node --> <xsl:function name="functx:siblings" as="node()*"> <xsl:param name="node" as="node()?"/> <xsl:sequence select=" $node/../node() except $node "/> </xsl:function> <!-- Sorts a sequence of numeric values or nodes @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_sort-as-numeric.html @param $seq the sequence to sort --> <xsl:function name="functx:sort-as-numeric" as="item()*"> <xsl:param name="seq" as="item()*"/> <xsl:for-each select="$seq"> <xsl:sort select="number(.)"/> <xsl:copy-of select="."/> </xsl:for-each> </xsl:function> <!-- Sorts a sequence of values or nodes regardless of capitalization @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_sort-case-insensitive.html @param $seq the sequence to sort --> <xsl:function name="functx:sort-case-insensitive" as="item()*"> <xsl:param name="seq" as="item()*"/> <xsl:for-each select="$seq"> <xsl:sort select="upper-case(string(.))"/> <xsl:copy-of select="."/> </xsl:for-each> </xsl:function> <!-- Sorts a sequence of nodes in document order @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_sort-document-order.html @param $seq the sequence to sort --> <xsl:function name="functx:sort-document-order" as="node()*"> <xsl:param name="seq" as="node()*"/> <xsl:sequence select=" $seq/. "/> </xsl:function> <!-- Sorts a sequence of values or nodes @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_sort.html @param $seq the sequence to sort --> <xsl:function name="functx:sort" as="item()*"> <xsl:param name="seq" as="item()*"/> <xsl:for-each select="$seq"> <xsl:sort select="."/> <xsl:copy-of select="."/> </xsl:for-each> </xsl:function> <!-- Performs substring-after, returning the entire string if it does not contain the delimiter @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_substring-after-if-contains.html @param $arg the string to substring @param $delim the delimiter --> <xsl:function name="functx:substring-after-if-contains" as="xs:string?"> <xsl:param name="arg" as="xs:string?"/> <xsl:param name="delim" as="xs:string"/> <xsl:sequence select=" if (contains($arg,$delim)) then substring-after($arg,$delim) else $arg "/> </xsl:function> <!-- The substring after the last text that matches a regex @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_substring-after-last-match.html @param $arg the string to substring @param $regex the regular expression --> <xsl:function name="functx:substring-after-last-match" as="xs:string"> <xsl:param name="arg" as="xs:string?"/> <xsl:param name="regex" as="xs:string"/> <xsl:sequence select=" replace($arg,concat('^.*',$regex),'') "/> </xsl:function> <!-- The substring after the last occurrence of a delimiter @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_substring-after-last.html @param $arg the string to substring @param $delim the delimiter --> <xsl:function name="functx:substring-after-last" as="xs:string"> <xsl:param name="arg" as="xs:string?"/> <xsl:param name="delim" as="xs:string"/> <xsl:sequence select=" replace ($arg,concat('^.*',functx:escape-for-regex($delim)),'') "/> </xsl:function> <!-- The substring after the first text that matches a regex @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_substring-after-match.html @param $arg the string to substring @param $regex the regular expression --> <xsl:function name="functx:substring-after-match" as="xs:string?"> <xsl:param name="arg" as="xs:string?"/> <xsl:param name="regex" as="xs:string"/> <xsl:sequence select=" replace($arg,concat('^.*?',$regex),'') "/> </xsl:function> <!-- Performs substring-before, returning the entire string if it does not contain the delimiter @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_substring-before-if-contains.html @param $arg the string to substring @param $delim the delimiter --> <xsl:function name="functx:substring-before-if-contains" as="xs:string?"> <xsl:param name="arg" as="xs:string?"/> <xsl:param name="delim" as="xs:string"/> <xsl:sequence select=" if (contains($arg,$delim)) then substring-before($arg,$delim) else $arg "/> </xsl:function> <!-- The substring after the first text that matches a regex @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_substring-before-last-match.html @param $arg the string to substring @param $regex the regular expression --> <xsl:function name="functx:substring-before-last-match" as="xs:string?"> <xsl:param name="arg" as="xs:string?"/> <xsl:param name="regex" as="xs:string"/> <xsl:sequence select=" replace($arg,concat('^(.*)',$regex,'.*'),'$1') "/> </xsl:function> <!-- The substring before the last occurrence of a delimiter @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_substring-before-last.html @param $arg the string to substring @param $delim the delimiter --> <xsl:function name="functx:substring-before-last" as="xs:string"> <xsl:param name="arg" as="xs:string?"/> <xsl:param name="delim" as="xs:string"/> <xsl:sequence select=" if (matches($arg, functx:escape-for-regex($delim))) then replace($arg, concat('^(.*)', functx:escape-for-regex($delim),'.*'), '$1') else '' "/> </xsl:function> <!-- The substring before the last text that matches a regex @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_substring-before-match.html @param $arg the string to substring @param $regex the regular expression --> <xsl:function name="functx:substring-before-match" as="xs:string"> <xsl:param name="arg" as="xs:string?"/> <xsl:param name="regex" as="xs:string"/> <xsl:sequence select=" tokenize($arg,$regex)[1] "/> </xsl:function> <!-- Construct a time from an hour, minute and second @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_time.html @param $hour the hour @param $minute the minute @param $second the second --> <xsl:function name="functx:time" as="xs:time"> <xsl:param name="hour" as="xs:anyAtomicType"/> <xsl:param name="minute" as="xs:anyAtomicType"/> <xsl:param name="second" as="xs:anyAtomicType"/> <xsl:sequence select=" xs:time( concat( functx:pad-integer-to-length(xs:integer($hour),2),':', functx:pad-integer-to-length(xs:integer($minute),2),':', functx:pad-integer-to-length(xs:integer($second),2))) "/> </xsl:function> <!-- Converts an xs:dayTimeDuration into a timezone like "-05:00" or "Z" @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_timezone-from-duration.html @param $duration the duration --> <xsl:function name="functx:timezone-from-duration" as="xs:string"> <xsl:param name="duration" as="xs:dayTimeDuration"/> <xsl:sequence select=" if (string($duration) = ('PT0S','-PT0S')) then 'Z' else if (matches(string($duration),'-PT[1-9]H')) then replace(string($duration),'PT([1-9])H','0$1:00') else if (matches(string($duration),'PT[1-9]H')) then replace(string($duration),'PT([1-9])H','+0$1:00') else if (matches(string($duration),'-PT1[0-4]H')) then replace(string($duration),'PT(1[0-4])H','$1:00') else if (matches(string($duration),'PT1[0-4]H')) then replace(string($duration),'PT(1[0-4])H','+$1:00') else error(xs:QName('functx:Invalid_Duration_Value')) "/> </xsl:function> <!-- The total number of days in a dayTimeDuration @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_total-days-from-duration.html @param $duration the duration --> <xsl:function name="functx:total-days-from-duration" as="xs:decimal?"> <xsl:param name="duration" as="xs:dayTimeDuration?"/> <xsl:sequence select=" $duration div xs:dayTimeDuration('P1D') "/> </xsl:function> <!-- The total number of hours in a dayTimeDuration @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_total-hours-from-duration.html @param $duration the duration --> <xsl:function name="functx:total-hours-from-duration" as="xs:decimal?"> <xsl:param name="duration" as="xs:dayTimeDuration?"/> <xsl:sequence select=" $duration div xs:dayTimeDuration('PT1H') "/> </xsl:function> <!-- The total number of minutes in a dayTimeDuration @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_total-minutes-from-duration.html @param $duration the duration --> <xsl:function name="functx:total-minutes-from-duration" as="xs:decimal?"> <xsl:param name="duration" as="xs:dayTimeDuration?"/> <xsl:sequence select=" $duration div xs:dayTimeDuration('PT1M') "/> </xsl:function> <!-- The total number of months in a yearMonthDuration @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_total-months-from-duration.html @param $duration the duration --> <xsl:function name="functx:total-months-from-duration" as="xs:decimal?"> <xsl:param name="duration" as="xs:yearMonthDuration?"/> <xsl:sequence select=" $duration div xs:yearMonthDuration('P1M') "/> </xsl:function> <!-- The total number of seconds in a dayTimeDuration @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_total-seconds-from-duration.html @param $duration the duration --> <xsl:function name="functx:total-seconds-from-duration" as="xs:decimal?"> <xsl:param name="duration" as="xs:dayTimeDuration?"/> <xsl:sequence select=" $duration div xs:dayTimeDuration('PT1S') "/> </xsl:function> <!-- The total number of years in a yearMonthDuration @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_total-years-from-duration.html @param $duration the duration --> <xsl:function name="functx:total-years-from-duration" as="xs:decimal?"> <xsl:param name="duration" as="xs:yearMonthDuration?"/> <xsl:sequence select=" $duration div xs:yearMonthDuration('P1Y') "/> </xsl:function> <!-- Trims leading and trailing whitespace @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_trim.html @param $arg the string to trim --> <xsl:function name="functx:trim" as="xs:string"> <xsl:param name="arg" as="xs:string?"/> <xsl:sequence select=" replace(replace($arg,'\s+$',''),'^\s+','') "/> </xsl:function> <!-- Updates the attribute value of an XML element @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_update-attributes.html @param $elements the element(s) for which you wish to update the attribute @param $attrNames the name(s) of the attribute(s) to add @param $attrValues the value(s) of the attribute(s) to add --> <xsl:function name="functx:update-attributes" as="element()?"> <xsl:param name="elements" as="element()*"/> <xsl:param name="attrNames" as="xs:QName*"/> <xsl:param name="attrValues" as="xs:anyAtomicType*"/> <xsl:for-each select="$elements"> <xsl:variable name="element" select="."/> <xsl:copy> <xsl:for-each select="$attrNames"> <xsl:variable name="seq" select="position()"/> <xsl:if test="$element/@*[node-name(.) = current()]"> <xsl:attribute name="{.}" namespace="{namespace-uri-from-QName(.)}" select="$attrValues[$seq]"/> </xsl:if> </xsl:for-each> <xsl:copy-of select="@*[not(node-name(.) = $attrNames)]|node()"/> </xsl:copy> </xsl:for-each> </xsl:function> <!-- The values in one sequence that aren't in another sequence @author W3C XML Query Working Group @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_value-except.html @param $arg1 the first sequence @param $arg2 the second sequence --> <xsl:function name="functx:value-except" as="xs:anyAtomicType*"> <xsl:param name="arg1" as="xs:anyAtomicType*"/> <xsl:param name="arg2" as="xs:anyAtomicType*"/> <xsl:sequence select=" distinct-values($arg1[not(.=$arg2)]) "/> </xsl:function> <!-- The intersection of two sequences of values @author W3C XML Query Working Group @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_value-intersect.html @param $arg1 the first sequence @param $arg2 the second sequence --> <xsl:function name="functx:value-intersect" as="xs:anyAtomicType*"> <xsl:param name="arg1" as="xs:anyAtomicType*"/> <xsl:param name="arg2" as="xs:anyAtomicType*"/> <xsl:sequence select=" distinct-values($arg1[.=$arg2]) "/> </xsl:function> <!-- The union of two sequences of values @author W3C XML Query Working Group @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_value-union.html @param $arg1 the first sequence @param $arg2 the second sequence --> <xsl:function name="functx:value-union" as="xs:anyAtomicType*"> <xsl:param name="arg1" as="xs:anyAtomicType*"/> <xsl:param name="arg2" as="xs:anyAtomicType*"/> <xsl:sequence select=" distinct-values(($arg1, $arg2)) "/> </xsl:function> <!-- The number of words @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_word-count.html @param $arg the string to measure --> <xsl:function name="functx:word-count" as="xs:integer"> <xsl:param name="arg" as="xs:string?"/> <xsl:sequence select=" count(tokenize($arg, '\W+')[. != '']) "/> </xsl:function> <!-- Turns a string of words into camelCase @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_words-to-camel-case.html @param $arg the string to modify --> <xsl:function name="functx:words-to-camel-case" as="xs:string"> <xsl:param name="arg" as="xs:string?"/> <xsl:sequence select=" string-join((tokenize($arg,'\s+')[1], for $word in tokenize($arg,'\s+')[position() > 1] return functx:capitalize-first($word)) ,'') "/> </xsl:function> <!-- Wraps a sequence of atomic values in XML elements @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_wrap-values-in-elements.html @param $values the values to wrap in elements @param $elementName the name of the elements to construct --> <xsl:function name="functx:wrap-values-in-elements" as="element()*"> <xsl:param name="values" as="xs:anyAtomicType*"/> <xsl:param name="elementName" as="xs:QName"/> <xsl:for-each select="$values"> <xsl:element name="{$elementName}" namespace="{namespace-uri-from-QName($elementName)}"> <xsl:sequence select="."/> </xsl:element> </xsl:for-each> </xsl:function> <!-- Construct a yearMonthDuration from a number of years and months @author Priscilla Walmsley, Datypic @version 1.0 @see http://www.xsltfunctions.com/xsl/functx_yearmonthduration.html @param $years the number of years @param $months the number of months --> <xsl:function name="functx:yearMonthDuration" as="xs:yearMonthDuration"> <xsl:param name="years" as="xs:decimal?"/> <xsl:param name="months" as="xs:integer?"/> <xsl:sequence select=" (xs:yearMonthDuration('P1M') * functx:if-empty($months,0)) + (xs:yearMonthDuration('P1Y') * functx:if-empty($years,0)) "/> </xsl:function> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" exclude-result-prefixes="#all" version="3.0" xml:lang="en"> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>ELS-COMMON lib : module "CONVERSION AND CASTING" utilities</xd:p> </xd:desc> </xd:doc> <!--conversion roman2numeric adapted from http://users.atw.hu/xsltcookbook2/xsltckbk2-chp-3-sect-3.html--> <!--An XML map decimal/roman numerals--> <xsl:variable name="els:roman-value" as="element(els:roman)+"> <els:roman value="1">I</els:roman> <els:roman value="5">V</els:roman> <els:roman value="10">X</els:roman> <els:roman value="50">L</els:roman> <els:roman value="100">C</els:roman> <els:roman value="500">D</els:roman> <els:roman value="1000">M</els:roman> </xsl:variable> <xd:doc>Implementation : recursiv template to convert roman numerals to decimal numbers</xd:doc> <xsl:template name="els:roman-to-number-impl" as="xs:string" visibility="private"> <xsl:param name="roman" as="xs:string"/> <xsl:param name="value" select="0" as="xs:integer"/> <xsl:variable name="len" select="string-length($roman)" as="xs:integer"/> <xsl:choose> <xsl:when test="not($len)"> <xsl:value-of select="$value"/> </xsl:when> <xsl:when test="$len = 1"> <xsl:value-of select="$value + $els:roman-value[. = $roman]/@value"/> </xsl:when> <xsl:otherwise> <xsl:variable name="roman-num" select="$els:roman-value[. = substring($roman, 1, 1)]" as="element(els:roman)?"/> <xsl:choose> <xsl:when test="$roman-num/following-sibling::els:roman = substring($roman, 2, 1)"> <xsl:call-template name="els:roman-to-number-impl"> <xsl:with-param name="roman" select="substring($roman,2,$len - 1)" as="xs:string"/> <xsl:with-param name="value" select="$value - xs:integer($roman-num/@value)" as="xs:integer"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:call-template name="els:roman-to-number-impl"> <xsl:with-param name="roman" select="substring($roman, 2, $len - 1)" as="xs:string"/> <xsl:with-param name="value" select="$value + xs:integer($roman-num/@value)" as="xs:integer"/> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:template> <xd:doc>Converts roman numerals to decimal numbers</xd:doc> <xsl:function name="els:roman2numeric" as="xs:string"> <xsl:param name="roman" as="xs:string"/> <xsl:choose> <xsl:when test="translate($roman, string-join($els:roman-value/text(), ''), '') != ''"> <xsl:text>NaN</xsl:text> </xsl:when> <xsl:otherwise> <xsl:call-template name="els:roman-to-number-impl"> <xsl:with-param name="roman" select="$roman" as="xs:string"/> </xsl:call-template> </xsl:otherwise> </xsl:choose> <!--debug test : <xsl:for-each select="('I','II','III','IV','V','VI','VII','VIII','IX','X','XI','XII','XIII','XIV','XV','XVI','XVII','XVIII','XIX','XX')"> <xsl:call-template name="els:crlf"/> <xsl:value-of select="."/><xsl:text>=</xsl:text><xsl:value-of select="els:roman2numeric(.)"/> </xsl:for-each>--> </xsl:function> <xd:doc>Convert a one character string to an numeric (representing the position in the alphabet)</xd:doc> <xsl:function name="els:litteral2numeric" as="xs:integer"> <xsl:param name="lit" as="xs:string"/> <xsl:value-of select="index-of(('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'), upper-case($lit))"/> </xsl:function> <xd:doc>Check if atomic value is an "number"</xd:doc> <!--FIXME : cf. http://www.xsltfunctions.com/xsl/functx_is-a-number.html--> <xsl:function name="els:isNumber" as="xs:boolean"> <xsl:param name="s" as="xs:string?"/> <xsl:choose> <xsl:when test="empty($s)"> <xsl:sequence select="false()"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="number($s) = number($s)"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc>Check if atomic value is an integer</xd:doc> <xsl:function name="els:isInteger" as="xs:boolean"> <xsl:param name="s" as="xs:string?"/> <xsl:choose> <xsl:when test="empty($s)"> <xsl:sequence select="false()"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="$s castable as xs:integer"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc>Check if atomic value is an anyURI</xd:doc> <xsl:function name="els:isAnyUri" as="xs:boolean"> <xsl:param name="item" as="item()?"/> <xsl:choose> <xsl:when test="empty($item)"> <xsl:sequence select="false()"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="$item castable as xs:anyURI"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc>1 arg signature of els:round. Default $precision = 0 (that's why it returns an integer)</xd:doc> <xsl:function name="els:round" as="xs:integer"> <xsl:param name="number" as="xs:double"/> <xsl:value-of select="els:round($number,0) cast as xs:integer"/> </xsl:function> <xd:doc>Get the round number of any $number with the specified $precision</xd:doc> <xsl:function name="els:round" as="xs:double"> <xsl:param name="number" as="xs:double"/> <xsl:param name="precision" as="xs:integer"/> <xsl:variable name="multiple" select="number(concat('10E',string($precision - 1))) cast as xs:integer" as="xs:integer"/> <!--for $i to $precision return 10--> <xsl:value-of select="round($number*$multiple) div $multiple"/> <!--cf. http://www.xsltfunctions.com/xsl/fn_round.html but no precision--> <!--FIXME : check the nativ function round-half-to-even($arg,$precision) It seems to do exactly the sampe : http://www.liafa.jussieu.fr/~carton/Enseignement/XML/Cours/XPath/index.html --> </xsl:function> <xd:doc>Converts hexadecimal number to decimal number</xd:doc> <xsl:function name="els:hexToDec" as="xs:integer?"> <xsl:param name="str" as="xs:string"/> <xsl:if test="$str != ''"> <xsl:variable name="len" select="string-length($str)" as="xs:integer"/> <xsl:value-of select=" if ( $len lt 2 ) then string-length(substring-before('0 1 2 3 4 5 6 7 8 9 AaBbCcDdEeFf', $str)) idiv 2 else xs:integer(els:hexToDec(substring($str, 1, $len - 1))) * 16 + xs:integer(els:hexToDec(substring($str, $len)))"/> </xsl:if> </xsl:function> <xd:doc>Converts decimal number to hexadecimal number</xd:doc> <xsl:function name="els:decToHex" as="xs:string"> <xsl:param name="n.decimal" as="xs:integer"/> <xsl:sequence select="if ($n.decimal eq 0) then '0' else concat( if ($n.decimal gt 16) then els:decToHex($n.decimal idiv 16) else '', substring('0123456789ABCDEF', ($n.decimal mod 16) + 1, 1))"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>DEPRECATED FUNCTION : USE els:convertAtomicValueToCanonicalBooleanValue($var,'fr') INSTEAD.</xd:p> <xd:p>Convert an atomic value to a boolean</xd:p> <xd:p>If the value is equal to "TRUE", "OUI", "VRAI", it returns true()</xd:p> </xd:desc> </xd:doc> <xsl:function name="els:convertToBoolean" as="xs:boolean"> <xsl:param name="var" as="item()?"/> <xsl:message>[WARNING] Function els:convertToBoolean($var) is deprecated and may be removed from future releases. Use els:convertAtomicValueToCanonicalBooleanValue($var,'fr') instead.</xsl:message> <xsl:sequence select="els:convertAtomicValueToCanonicalBooleanValue($var,'fr')"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Converts an atomic value to a xs:boolean in its canonical form (true() / false()).</xd:p> <xd:p>The <xd:ref name="lang" type="parameter">$lang</xd:ref> parameter allows the conversion of non-canonical string forms:</xd:p> <xd:ul> <xd:li>$lang = 'fr': 'OUI' / 'VRAI'.</xd:li> <xd:li>$lang = 'en': 'YES'.</xd:li> </xd:ul> </xd:desc> <xd:param name="var">[item()?] An atomic value.</xd:param> <xd:param name="lang">[xs:string] A language code for non-canonical string forms.</xd:param> <xd:return>[xs:boolean] The boolean converted atomic value in its canonical form.</xd:return> </xd:doc> <xsl:function name="els:convertAtomicValueToCanonicalBooleanValue" as="xs:boolean"> <xsl:param name="var" as="item()?"/> <xsl:param name="lang" as="xs:string"/> <xsl:value-of select="if (not(exists($var))) then (false()) else ( if ($var castable as xs:boolean) then ($var cast as xs:boolean) else ( if ($var instance of xs:string and $lang = 'fr') then (boolean(upper-case($var) = 'OUI' or upper-case($var) = 'VRAI')) else ( if ($var instance of xs:string and $lang = 'en') then (boolean(upper-case($var) = 'YES')) else (false()) ) ) )"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Converts an atomic value to a xs:boolean in its canonical form (true() / false()).</xd:p> <xd:p>The <xd:ref name="lang" type="parameter">$lang</xd:ref> parameter allows the conversion of non-canonical string forms.</xd:p> <xd:p>The <xd:ref name="lang" type="parameter">$lang</xd:ref> default value is "fr".</xd:p> </xd:desc> <xd:param name="var">[item()?] An atomic value.</xd:param> <xd:return>[xs:boolean] The boolean converted atomic value in its canonical form.</xd:return> </xd:doc> <xsl:function name="els:convertAtomicValueToCanonicalBooleanValue" as="xs:boolean"> <xsl:param name="var" as="item()?"/> <xsl:sequence select="els:convertAtomicValueToCanonicalBooleanValue($var,'fr')"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Converts an atomic value to a xs:boolean in its integer form (1 / 0).</xd:p> <xd:p>The <xd:ref name="lang" type="parameter">$lang</xd:ref> parameter allows the conversion of non-canonical string forms:</xd:p> <xd:ul> <xd:li>$lang = 'fr': 'OUI' / 'VRAI'.</xd:li> <xd:li>$lang = 'en': 'YES'.</xd:li> </xd:ul> </xd:desc> <xd:param name="var">[item()?] An atomic value.</xd:param> <xd:param name="lang">[xs:string] A language code for non-canonical string forms.</xd:param> <xd:return>[xs:integer] The boolean converted atomic value in its integer form.</xd:return> </xd:doc> <xsl:function name="els:convertAtomicValueToIntegerBooleanValue" as="xs:integer"> <xsl:param name="var" as="item()?"/> <xsl:param name="lang" as="xs:string"/> <xsl:value-of select="if (not(exists($var))) then (0) else ( if ($var castable as xs:boolean) then (els:convertCanonicalBooleanValueToIntegerBooleanValue($var cast as xs:boolean)) else ( if ($var instance of xs:string and $lang = 'fr') then (els:convertCanonicalBooleanValueToIntegerBooleanValue(upper-case($var) = 'OUI' or upper-case($var) = 'VRAI')) else ( if ($var instance of xs:string and $lang = 'en') then (els:convertCanonicalBooleanValueToIntegerBooleanValue(upper-case($var) = 'YES')) else (0) ) ) )"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Converts an atomic value to a xs:boolean in its integer form (1 / 0).</xd:p> <xd:p>The <xd:ref name="lang" type="parameter">$lang</xd:ref> parameter allows the conversion of non-canonical string forms.</xd:p> <xd:p>The <xd:ref name="lang" type="parameter">$lang</xd:ref> default value is "fr".</xd:p> </xd:desc> <xd:param name="var">[item()?] An atomic value.</xd:param> <xd:return>[xs:integer] The boolean converted atomic value in its integer form.</xd:return> </xd:doc> <xsl:function name="els:convertAtomicValueToIntegerBooleanValue" as="xs:integer"> <xsl:param name="var" as="item()?"/> <xsl:sequence select="els:convertAtomicValueToIntegerBooleanValue($var,'fr')"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Converts an xs:boolean in its canonical form (true() / false()) to its integer form (1 / 0).</xd:p> </xd:desc> <xd:param name="val">[xs:boolean] A boolean value.</xd:param> <xd:return>[xs:integer] The boolean value in its integer form.</xd:return> </xd:doc> <xsl:function name="els:convertCanonicalBooleanValueToIntegerBooleanValue" as="xs:integer"> <xsl:param name="val" as="xs:boolean"/> <xsl:value-of select="if ($val = true()) then (1) else (0)"/> </xsl:function> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saxon="http://saxon.sf.net/" xmlns:functx="http://www.functx.com" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" exclude-result-prefixes="#all" version="3.0"> <xsl:import href="els-common.xsl"/> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>Librairie de fonctions / templates pour la gestion des logs aux ELS.</xd:p> </xd:desc> </xd:doc> <!--=================================================== --> <!-- PARAMS --> <!--=================================================== --> <xd:doc> <xd:desc> <xd:p>Niveau à partir duquel les logs sont</xd:p> <xd:ul> <xd:li>affichés sur la console via un xsl:message (log.level.alert)</xd:li> <xd:li>génèrés via un élément "log" dans le document source (log.level.markup)</xd:li> </xd:ul> <xd:p>La valeur de ces paramètres est à définir dans la XSLT utilisant les logs</xd:p> <xd:p>Si ce n'est pas le cas, ce sont les valeurs des paramêtres alert et markup dans la f° de log qui définissent seuls la génération des logs. </xd:p> </xd:desc> </xd:doc> <xsl:param name="els:log.level.alert" as="xs:string?" required="no"/> <xsl:param name="els:log.level.markup" as="xs:string?" required="no"/> <xd:doc> <xd:desc> <xd:p>paramêtre permettant de déactiver complètement les log.</xd:p> </xd:desc> </xd:doc> <xsl:param name="els:log.enable" as="xs:boolean?" required="no" select="true()"/> <!--=================================================== --> <!-- LOG and MESSAGES --> <!--=================================================== --> <xd:doc> <xd:desc> <xd:p>Log des erreurs ou warning xslt</xd:p> </xd:desc> <xd:param name="xsltName">Nom de la xslt appelante. Typiquement : "els:getFileName(static-base-uri())"</xd:param> <xd:param name="level">Level du log : (info | debug | warning | error | fatal | fixme | todo)</xd:param> <xd:param name="code">Code erreur pour s'y retrouver plus facilement (peut servir à filter les erreurs "dpm / dsi" ainsi qu'a faire des requête xpath pour compter le nombre d'erreurs d'un code spécifique</xd:param> <xd:param name="alert">Détermine si on génère un xsl:message ou pas</xd:param> <xd:param name="markup">Détermine si on génère un élément "log" en sortie ou pas</xd:param> <xd:param name="description">Description de l'erreur</xd:param> <xd:param name="xpath">XPath spécifique. Si omis le xpath est calculé en fonction du contexte courant</xd:param> <xd:param name="base-uri">URI du fichier pour lequel le log est créé</xd:param> </xd:doc> <xsl:template name="els:log"> <xsl:param name="xsltName" as="xs:string" required="yes"/> <xsl:param name="level" select="'info'" as="xs:string"/> <xsl:param name="code" select="'undefined'" as="xs:string"/> <xsl:param name="alert" select="if ($level = 'error' or $level = 'fatal') then (true()) else (false())" as="xs:boolean"/> <xsl:param name="markup" select="true()" as="xs:boolean"/> <xsl:param name="description" as="item()*"/> <xsl:param name="logXpath" select="false()" as="xs:boolean"/> <xsl:param name="xpathContext" select="." as="item()"/> <xsl:param name="xpath" as="xs:string?" required="no"/> <xsl:param name="base-uri" as="xs:string?" required="no"/> <!--Si $logXpath=false() pas la peine de risquer une erreur sur un $xpathContext "." qui pourrait ne pas exister (dans un analyze-string par exemple "." est un string pas un context xpath)--> <xsl:if test="$els:log.enable"> <xsl:variable name="xpath" select=" if (exists($xpath)) then ($xpath) else (if ($logXpath) then (els:get-xpath($xpathContext)) else (''))" as="xs:string"/> <!--checking param--> <xsl:variable name="levelValues" select="('info','debug','warning','error', 'fatal','fixme','todo')" as="xs:string*"/> <xsl:if test="not(some $levelName in $levelValues satisfies $level = $levelName)"> <xsl:call-template name="els:log"> <!--<xsl:with-param name="xsltName" select="tokenize(static-base-uri(),'/')[last()]"/> ne fonctionne pas en java pour hervé Rolland --> <xsl:with-param name="xsltName" select="'els-log.xsl'"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="xpathContext" select="$xpathContext"/> <xsl:with-param name="description" xml:space="preserve">Appel du template log avec valeur du parametre level = "<xsl:value-of select="$level"/>" non autorisé</xsl:with-param> </xsl:call-template> </xsl:if> <!--logging par xsl:message si $alert (c'est-à-dire explicitement demandé ou level approprié) et niveau de log configuré pour être traité --> <xsl:variable name="alertWithLevelToProcess" select="if (exists($els:log.level.alert)) then (els:isLogToBeProcessed($level, $els:log.level.alert)) else ($alert)"/> <xsl:if test="$alertWithLevelToProcess"> <xsl:variable name="msg"> <xsl:text>[</xsl:text> <xsl:value-of select="upper-case($level)"/> <xsl:text>][</xsl:text> <xsl:if test="exists($base-uri)"> <xsl:value-of select="concat(tokenize($base-uri, '/')[last()], ' / ')"/> </xsl:if> <xsl:value-of select="$xsltName"/> <xsl:text>][</xsl:text> <xsl:value-of select="$code"/> <xsl:text>] </xsl:text> <!--suppression des accents car mal géré au niveau des invites de commande--> <xsl:sequence select="els:normalize-no-diacritic($description)"/> <xsl:if test="$logXpath"> <xsl:text> xpath=</xsl:text> <xsl:value-of select="$xpath"/> </xsl:if> </xsl:variable> <xsl:choose> <xsl:when test="$level = 'fatal'"> <!--<xsl:message terminate="yes" select="$msg"/>--> <xsl:message terminate="no" select="$msg"/> <!--On préfère ne jamais tuer le process, on pourra compter le nombre d'erreurs fatal même si risque d'effet "boule de neige"--> </xsl:when> <xsl:otherwise> <xsl:message terminate="no" select="$msg"/> </xsl:otherwise> </xsl:choose> </xsl:if> <!--logging via balise log si $markup et niveau de log configuré pour être traité --> <xsl:variable name="markupAndLevelToProcess" select="if (exists($els:log.level.markup)) then ($markup and els:isLogToBeProcessed($level, $els:log.level.markup)) else ($markup)"/> <xsl:if test="$markupAndLevelToProcess"> <els:log level="{$level}" code="{$code}" xsltName="{$xsltName}"> <xsl:if test="$logXpath"> <xsl:attribute name="xpath" select="$xpath"/> </xsl:if> <xsl:if test="$xpathContext instance of node()"> <!--que l'on soit sur un noeud attribut ou element ou autre, on créer un attribut avec le nom de l'élément "courant"--> <xsl:attribute name="element" select="name($xpathContext/ancestor-or-self::*[1])"/> </xsl:if> <!-- Mise en commentaire permet d'éviter d'ajouter du contenu textuel--> <!-- (Même si $description contient déjà un commentaire ou un "double tiret", la serialisation xsl:comment fonctionnera ! (testé) ) --> <xsl:comment><xsl:sequence select="$description"/></xsl:comment> </els:log> </xsl:if> </xsl:if> </xsl:template> <xd:doc> <xd:desc>Récupération de la priorité d'un niveau</xd:desc> </xd:doc> <xsl:function name="els:getLevelPriority" as="xs:integer"> <xsl:param name="level" as="xs:string"/> <xsl:choose> <xsl:when test="$level='fatal'">50000</xsl:when> <xsl:when test="$level='error'">40000</xsl:when> <xsl:when test="$level='warning'">30000</xsl:when> <xsl:when test="$level='info'">20000</xsl:when> <xsl:when test="$level='debug'">10000</xsl:when> <!-- TO DO : Fix temporaire suite au problème de compilation de cette XSLT avec Saxon 9.7 Bug #3069 remonté auprès de Saxonica (https://saxonica.plan.io/issues/3069) Michael Kay : The diagnostics suggest that it's caused by (some kind of failure during) optimization of the xsl:choose [...] (because all branches have the same form $v=X, it generates a switch expression which uses hashing rather than a sequential search). As a workaround, you could suppress this optimization by adding a dummy branch to the xsl:choose, e.g. xsl:when test="current-date() lt xs:date('1900-01-01'). --> <xsl:when test="current-date() lt xs:date('1900-01-01')">0</xsl:when> <!--<xsl:otherwise>0</xsl:otherwise>--> </xsl:choose> </xsl:function> <xd:doc> <xd:desc>Vérifie si les logs d'un niveau donné sont à traiter en fonction d'un flag indiquant quels niveaux sont à traiter</xd:desc> <xd:desc> <xd:p>Ce flag correspond </xd:p> <xd:ul> <xd:li> <xd:p>soit au premier niveau dans l'ordre des priorités pour lequel les logs doivent être traités</xd:p> <xd:p>- log d'un niveau avec priorité supérieure ou égale : traité</xd:p> <xd:p>- log d'un niveau avec priorité inférieure : non traité</xd:p> </xd:li> <xd:li>soit à "all" : tous les logs, quel que soit leur niveau, sont à traiter</xd:li> <xd:li>soit à "off" : aucun log, quel que soit son niveau, n'est à traiter</xd:li> </xd:ul> </xd:desc> </xd:doc> <xsl:function name="els:isLogToBeProcessed" as="xs:boolean"> <xsl:param name="level" as="xs:string"/> <xsl:param name="levelProcessFlag" as="xs:string"/> <xsl:value-of select="if ($levelProcessFlag = 'all') then (true()) else (if ($levelProcessFlag = 'off') then (false()) else (boolean(els:getLevelPriority($level) >= els:getLevelPriority($levelProcessFlag))))"/> </xsl:function> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" exclude-result-prefixes="#all" version="3.0" xml:lang="en"> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>Generic XSL functions/templates library used at ELS</xd:p> </xd:desc> </xd:doc> <!--<xsl:import href="functx.xsl"/> already imported within modules--> <xsl:import href="els-common_constants.xsl"/> <xsl:import href="els-common_dates.xsl"/> <xsl:import href="els-common_strings.xsl"/> <xsl:import href="els-common_xml.xsl"/> <xsl:import href="els-common_files.xsl"/> <xsl:import href="els-common_convert-cast.xsl"/> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:err="http://www.w3.org/2005/xqt-errors" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saxon="http://saxon.sf.net/" xmlns:functx="http://www.functx.com" xmlns:xslLib="http://www.lefebvre-sarrut.eu/ns/els/xslLib" exclude-result-prefixes="#all" version="3.0"> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>This XSLT convert XJSON xml representation to text JSON</xd:p> <xd:p>It uses XSLT 3.0 xml-to-json($e) function, which need as $e a valid XJSON xml.</xd:p> <xd:p>XJSON is the name we gave to the W3C xml JSON representation with schema : ext-models:/ext-models/w3c/xjson/schema-for-json.xsd</xd:p> </xd:desc> </xd:doc> <!--Named output so it does't take precedence when this XSLT is called. This XSLT produce a JSON string so the output should be "text" : - "json" output would be wrong cause it will escape the json string one more time - "xml" would also work with omit-xml-declaration setted to true --> <xsl:output method="text" name="xslLib:xjson2json"/> <!--Default serialization option for json--> <!--cf. https://www.w3.org/TR/xslt-30/#func-xml-to-json--> <xsl:param name="xslLib:xjson2json.options" select="map{'indent':false()}" as="map(*)"/> <!--==============================================--> <!--INIT--> <!--==============================================--> <xsl:template match="/"> <xsl:apply-templates select="." mode="xslLib:xjson2json"/> </xsl:template> <!--==============================================--> <!--MAIN--> <!--==============================================--> <xsl:template match="/" mode="xslLib:xjson2json"> <xsl:call-template name="xslLib:xjson2json.serialize-as-json"> <xsl:with-param name="json" select="xslLib:xjson2json(fn:*)" as="xs:string"/> </xsl:call-template> </xsl:template> <!--Specific template to serialize to JSON with Has been made specific because XSPEC would raise the error : XTDE1480: Cannot execute xsl:result-document while evaluating variable (xspec creates a variable with the ouput) When using XSPEC : override this template (get rid of the xsl:result-document here) --> <xsl:template name="xslLib:xjson2json.serialize-as-json"> <xsl:param name="json" required="yes" as="xs:string"/> <!--no @href cause we juste want to use the xsl:output defined for json on the main result--> <xsl:result-document format="xslLib:xjson2json"> <xsl:sequence select="$json"/> </xsl:result-document> </xsl:template> <!--1 arg signature--> <xsl:function name="xslLib:xjson2json" as="xs:string"> <xsl:param name="xjson" as="element(fn:map)"/> <xsl:sequence select="xslLib:xjson2json($xjson, $xslLib:xjson2json.options)"/> </xsl:function> <xsl:function name="xslLib:xjson2json" as="xs:string"> <xsl:param name="xjson" as="element(fn:map)"/> <xsl:param name="options" as="map(*)"/> <xsl:try select="xml-to-json($xjson, $options)"> <xsl:catch> <!--conversion errors are also jsonified--> <xsl:variable name="err" as="element()"> <fn:map><fn:string key="error"><xsl:value-of select="$err:code || ' : ' || $err:description"/></fn:string></fn:map> </xsl:variable> <xsl:value-of select="xml-to-json($err, $options)"/> </xsl:catch> </xsl:try> </xsl:function> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xf="http://www.lefebvre-sarrut.eu/ns/xmlfirst" xmlns:xfRes="http://www.lefebvre-sarrut.eu/ns/xmlfirst/ecm/resources" xmlns:xfe="http://www.lefebvre-sarrut.eu/ns/xmlfirst/xmlEditor" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" xmlns:xslLib="http://www.lefebvre-sarrut.eu/ns/els/xslLib" xmlns="http://www.w3.org/1999/xhtml" xpath-default-namespace="http://www.w3.org/1999/xhtml" exclude-result-prefixes="#all" version="3.0"> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>Génère une vue HTML de prévisualisation de l'EE.</xd:p> <xd:p>Il s'agit de la vue utilisée dans le panneau de droite de la fiche de l'EE et lors de la prévisualisation d'une EE dans les résultats de recherche ou les arbres.</xd:p> <xd:p>Importe la transformation utilisée pour l'éditeur XML (xfe-XML2HTML.xsl) avec fichier de configuration customisé pour remonter quelques informations supplémentaires.</xd:p> </xd:desc> </xd:doc> <!-- IMPORTS --> <xsl:import href="xfe:/xfe/xsl/xfe-XML2HTML.xsl"/> <xsl:import href="el_injectionJsTable.xsl"/> <!--XFE--> <!-- Paramètre obligatoire pour xfe:xml2html --> <xsl:param name="xfe:conf.uri" select="resolve-uri('_common/el_FICHE_FP.htmlPreview.xfe-conf.xml',static-base-uri())" as="xs:string"/> <xsl:param name="xfe:addXmlModelPi" select="false()" as="xs:boolean"/> <xsl:param name="xfe:addHTML5DOCTYPE" select="false()" as="xs:boolean"/> <xsl:param name="xfe:debug" select="false()" as="xs:boolean"/> <xsl:param name="xfe:addXfeLabel" select="false()" as="xs:boolean"/> <xsl:param name="xfe:fillHeadTitle" select="true()" as="xs:boolean"/> <xsl:param name="xfe:allowUnValidXML" select="true()" as="xs:boolean"/> <!--CSS--> <xsl:param name="xfe:css.path" select="'../../../../main/resources/el/'" as="xs:string"/> <xsl:param name="xfe:css.name" select="'xf_GB_FP.css'" as="xs:string"/> <!--CALS--> <!--Pas de style sur les bordures ou autre, sera géré en css par type de tableau--> <xsl:param name="xslLib:cals2html.use-style-insteadOf-class" select="false()" as="xs:boolean"/> <!--+==================================================+ | INIT | +==================================================+--> <!--No @mode for standalone execution--> <xsl:template match="/"> <xsl:apply-templates select="." mode="xfRes:EL_TEE_fichePratique.htmlSimplePreview"/> </xsl:template> <!--+==================================================+ | MAIN | +==================================================+--> <xsl:template match="/" mode="xfRes:EL_TEE_fichePratique.htmlSimplePreview"> <xsl:message>[INFO] Prévisualisation HTML de l'EE : <xsl:value-of select="base-uri()"/></xsl:message> <xsl:variable name="step" select="." as="document-node()"/> <!-- Application de la transfoHTML pour l'éditeur XML --> <!-- modification pour injecter du javascript --> <xsl:variable name="step" as="document-node()"> <xsl:document> <xsl:apply-templates select="$step" mode="xfe:xml2html"/> </xsl:document> </xsl:variable> <xsl:variable name="step" as="document-node()"> <xsl:document> <xsl:apply-templates select="$step" mode="xfRes:EL_TEE_fichePratique.adaptHTML"/> </xsl:document> </xsl:variable> <!--FINALY--> <xsl:apply-templates select="$step" mode="injectJS"/> </xsl:template> <!--============================================--> <!--xfRes:EL_TEE_fichePratique.adaptHTML--> <!--============================================--> <!-- Wrapping des elements groupes --> <xsl:template match="*[not(self::ul)][li]" mode="xfRes:EL_TEE_fichePratique.adaptHTML" priority="1"> <xsl:variable name="wrapper" as="element()"><ul/></xsl:variable> <xsl:apply-templates select="els:wrap-elements-adjacent-by-names(., 'li', $wrapper)" mode="#current"/> </xsl:template> <xsl:template match="*[not(self::footer)][aside]" mode="xfRes:EL_TEE_fichePratique.adaptHTML"> <xsl:variable name="wrapper" as="element()"><footer/></xsl:variable> <xsl:apply-templates select="els:wrap-elements-adjacent-by-names(., 'aside', $wrapper)" mode="#current"/> </xsl:template> <xsl:template match="node() | @*" mode="xfRes:EL_TEE_fichePratique.adaptHTML"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns="http://www.w3.org/1999/xhtml" xmlns:saxon="http://saxon.sf.net/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" xmlns:xf="http://www.lefebvre-sarrut.eu/ns/xmlfirst" xmlns:xfe="http://www.lefebvre-sarrut.eu/ns/xmlfirst/xmlEditor" xmlns:xslLib="http://www.lefebvre-sarrut.eu/ns/els/xslLib" xmlns:cals="http://docs.oasis-open.org/ns/oasis-exchange/table" xmlns:html="http://www.w3.org/1999/xhtml" exclude-result-prefixes="#all" version="3.0"> <xsl:import href="xfe-common.xsl"/> <xsl:import href="xslLib:/xslLib/cals2html.xsl"/> <xsl:import href="xslLib:/xslLib/xml2simpleHtml.xsl"/> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>Conv XML vers HTML d'un contentNode pour XFE</xd:p> </xd:desc> </xd:doc> <!--CALS2HTML params--> <!--FE-124 : don't use "colgroup" in html table--> <xsl:param name="xslLib:cals2html.compute-column-width-within-colgroup" select="false()" as="xs:boolean"/> <xsl:param name="xslLib:cals2html-keep-unmatched-attributes" select="true()" as="xs:boolean"/> <xsl:param name="xslLib:cals2html-unmatched-attributes-prefix" select="$xfe:dataXmlAttribute.prefix" as="xs:string"/> <!--When the EE has multiple contentNode, get the id of the one to be edited--> <xsl:param name="xfe:contentNodeId" select="''" as="xs:string"/> <xsl:param name="xfe:generateCompleteHtmlStructure" select="true()" as="xs:boolean"/> <xsl:param name="xfe:addHTML5DOCTYPE" select="true()" as="xs:boolean"/> <xsl:param name="xfe:addXmlModelPi" select="true()" as="xs:boolean"/> <xsl:param name="xfe:fillHeadTitle" select="false()" as="xs:boolean"/><!--FE-105 : pas de contenu dans le titre--> <xsl:param name="xfe:addXfeLabel" select="true()" as="xs:boolean"/> <!--param to prevent throughing a fatal error when unexpected xml element found--> <xsl:param name="xfe:allowUnValidXML" select="if($xfe:conf.hasSchema) then(false()) else(true())" as="xs:boolean"/> <!--Le doctype xhtml ajoute des méta spécifiques qui ne sont pas reproduites dans xspec (qui ignore vraissemblablement xsl:output)--> <!--FE-130 : we have to force omit-xml-declaration="yes" because it's not possible to add a parameter for this (except using xsl:result-document which is not the case here)--> <xsl:output method="xhtml" indent="no" omit-xml-declaration="yes"/> <!--Le vrai DOCTYPE html5 serait avec method="html" version="5.0" Mais cela pose des problème de balise non fermée (http://markmail.org/message/jaajiozvbbhqeipz) => cf. ajout manuel du DOCTYPE HTML5 --> <!--================================--> <!--INIT--> <!--================================--> <xsl:template match="/"> <xsl:apply-templates select="." mode="xfe:xml2html"/> </xsl:template> <!--================================--> <!--MAIN--> <!--================================--> <xsl:template match="/" mode="xfe:xml2html" priority="1"> <!--Overiding xfe:contentNodeId param so we can change it by calling this template only--> <xsl:param name="xfe:contentNodeId" select="$xfe:contentNodeId" as="xs:string"/> <xsl:variable name="contentNodes" select=".//xf:contentNode" as="element()*"/> <xsl:choose> <xsl:when test="not(xf:editorialEntity)"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'error'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[ERROR][XFE] Document must be an editorialEntity, but we continue for test</xsl:with-param> </xsl:call-template> <xsl:next-match/> </xsl:when> <xsl:when test="count($contentNodes) = 0"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'fatal'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[FATAL][XFE] No contentNode found in this EE</xsl:with-param> </xsl:call-template> <xsl:message terminate="yes"/> </xsl:when> <xsl:when test="count($contentNodes) = 1"> <xsl:apply-templates select="$contentNodes[1]/xf:content/*" mode="#current"/> </xsl:when> <xsl:otherwise> <xsl:variable name="contentNode" select="$contentNodes[@xf:id = $xfe:contentNodeId]" as="element()?"/> <xsl:choose> <xsl:when test="count($contentNode) = 0"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'fatal'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[FATAL][XFE] No contentNode with id="<xsl:value-of select="$xfe:contentNodeId"/>" found in this EE</xsl:with-param> </xsl:call-template> <xsl:message terminate="yes"/> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="$contentNode/xf:content/*" mode="#current"/> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:template> <!--On garde la possibilité d'avoir un contentNode en entrée (/) pour que les sample continuent de fonctionner, même si ce n'est pas la cible dans l'ECM (on aura toujours une EE en entrée)--> <!--Cela permets de travailler ici sur des sample valides selon le modèle srng de la conf--> <xsl:template match="/ | xf:content/*" mode="xfe:xml2html"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[INFO] xfe:conf.uri=<xsl:value-of select="$xfe:conf.uri"/></xsl:with-param> </xsl:call-template> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[INFO] xfe:debug=<xsl:value-of select="$xfe:debug"/><xsl:if test="not($xfe:debug)"> (les log de la transformation ne seront pas écrits sur le filesytem)</xsl:if></xsl:with-param> </xsl:call-template> <xsl:variable name="root" as="document-node()"> <xsl:document> <xsl:sequence select="."/> </xsl:document> </xsl:variable> <xsl:call-template name="xfe:log.normalizeConf"/> <!--<xsl:copy-of select="."/>--> <!--STEP 0--> <xsl:variable name="step" as="document-node()"> <xsl:document> <xsl:choose> <xsl:when test="parent::xf:content"> <xsl:apply-templates select="." mode="xfe:xml2html_resolveRelation"/> </xsl:when> <xsl:otherwise> <xsl:copy-of select="."/> </xsl:otherwise> </xsl:choose> </xsl:document> </xsl:variable> <xsl:if test="$xfe:debug"> <xsl:variable name="step.log.uri" select="resolve-uri('XML2HTML.step0_xml2html_resolveRelation.log.xml', $log.uri)" as="xs:anyURI"/> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[INFO] writing <xsl:value-of select="$step.log.uri"/></xsl:with-param> </xsl:call-template> <xsl:result-document href="{$step.log.uri}"> <xsl:sequence select="$step"/> </xsl:result-document> </xsl:if> <!--STEP 1--> <xsl:variable name="step" as="document-node()"> <xsl:choose> <xsl:when test="$xfe:conf.hasSchema"> <xsl:document> <xsl:apply-templates select="$step" mode="xfe:xml2html_annotations"/> </xsl:document> </xsl:when> <xsl:otherwise> <xsl:sequence select="$step"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:if test="$xfe:debug"> <xsl:variable name="step.log.uri" select="resolve-uri('XML2HTML.step1_xml2html_annotation.log.xml', $log.uri)" as="xs:anyURI"/> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[INFO] writing <xsl:value-of select="$step.log.uri"/></xsl:with-param> </xsl:call-template> <xsl:result-document href="{$step.log.uri}"> <xsl:sequence select="$step"/> </xsl:result-document> </xsl:if> <!--STEP 2--> <xsl:variable name="step" as="document-node()"> <xsl:document> <xsl:apply-templates select="$step" mode="xfe:xml2html_main"/> </xsl:document> </xsl:variable> <xsl:if test="$xfe:debug"> <xsl:variable name="step.log.uri" select="resolve-uri('XML2HTML.step1_xml2html_main.log.xml', $log.uri)" as="xs:anyURI"/> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[INFO] writing <xsl:value-of select="$step.log.uri"/></xsl:with-param> </xsl:call-template> <xsl:result-document href="{$step.log.uri}"> <xsl:sequence select="$step"/> </xsl:result-document> </xsl:if> <!--STEP 3--> <xsl:variable name="step" as="document-node()"> <xsl:document> <xsl:apply-templates select="$step" mode="xslLib:cals2html"/> </xsl:document> </xsl:variable> <xsl:if test="$xfe:debug"> <xsl:variable name="step.log.uri" select="resolve-uri('XML2HTML.step2_cals2html.log.xml', $log.uri)" as="xs:anyURI"/> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[INFO] writing <xsl:value-of select="$step.log.uri"/></xsl:with-param> </xsl:call-template> <xsl:result-document href="{$step.log.uri}"> <xsl:sequence select="$step"/> </xsl:result-document> </xsl:if> <!--STEP 4--> <xsl:variable name="step" as="document-node()"> <xsl:document> <xsl:apply-templates select="$step" mode="xfe:xml2html_step3_moveInlineNotes"/> </xsl:document> </xsl:variable> <xsl:if test="$xfe:debug"> <xsl:variable name="step.log.uri" select="resolve-uri('XML2HTML.step3_moveInlineNotes.log.xml', $log.uri)" as="xs:anyURI"/> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[INFO] writing <xsl:value-of select="$step.log.uri"/></xsl:with-param> </xsl:call-template> <xsl:result-document href="{$step.log.uri}"> <xsl:sequence select="$step"/> </xsl:result-document> </xsl:if> <!--STEP 5--> <xsl:variable name="step" as="document-node()"> <xsl:document> <xsl:apply-templates select="$step" mode="xslLib:xml2html_customizeCals2html"/> </xsl:document> </xsl:variable> <xsl:if test="$xfe:debug"> <xsl:variable name="step.log.uri" select="resolve-uri('XML2HTML.step4_customizeCals2html.log.xml', $log.uri)" as="xs:anyURI"/> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[INFO] writing <xsl:value-of select="$step.log.uri"/></xsl:with-param> </xsl:call-template> <xsl:result-document href="{$step.log.uri}"> <xsl:sequence select="$step"/> </xsl:result-document> </xsl:if> <!--FINALY--> <xsl:choose> <xsl:when test="$xfe:generateCompleteHtmlStructure"> <xsl:variable name="xfe:srng.name" select="els:getFileName($xfe:conf.normalized/*:srngXmlmodel/@href, false())" as="xs:string"/> <xsl:if test="$xfe:addXmlModelPi and $xfe:conf.hasSchema"> <xsl:processing-instruction name="xml-model"> <xsl:text>href="</xsl:text> <xsl:value-of select="els:getRelativePath(els:getFolderPath(base-uri()), concat(els:getFolderPath($xfe:srng.uri), '/', $xfe:srng.name, '.html.rng'))"/> <xsl:text>" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"</xsl:text> </xsl:processing-instruction> </xsl:if> <!--Puisqu'on veut éviter des problème de balise non fermées à la sérialisation en local, on ajoute ce doctype pour html5 avec une vielle méthode--> <xsl:if test="$xfe:addHTML5DOCTYPE"> <xsl:text disable-output-escaping="yes"><!DOCTYPE html></xsl:text> </xsl:if> <html> <head> <!--<meta charset="UTF-8"/> FIXME : pour html5--> <title> <xsl:if test="$xfe:fillHeadTitle"> <xsl:value-of select="els:evaluate-xpath($xfe:conf.normalized/*:title/@xpath, $root/*)"/> </xsl:if> </title> <xsl:variable name="css.path" select="($xfe:css.path, $xfe:conf.normalized/*:css/@path, '')[1]" as="xs:string"/> <xsl:variable name="css.path.rel" select="if (els:isAbsoluteUri($css.path)) then (els:getRelativePath(els:getFolderPath(base-uri()),$css.path)) else ($css.path)" as="xs:string"/> <xsl:variable name="css.name" select="($xfe:css.name, $xfe:conf.normalized/*:css/@name, concat($xfe:srng.name, '.css'))[1]" as="xs:string"/> <link type="text/css" rel="Stylesheet" href="{concat($css.path.rel, if(normalize-space($css.path.rel) != '' and not(ends-with($css.path.rel, '/'))) then('/') else(''), $css.name)}"/> <!--FIXME : impossible de distinguer les tableaux cals ou html natif, de toute façon pour l'édition mieux vaut ne pas mettre de css ici mais tout mettre en attribut (@style si besoin), servira notamment à la rétro-conv HTML2XML--> <!--<link type="text/css" rel="Stylesheet" href="../../cals2html.css"/>--> <!--<xsl:result-document href="{resolve-uri('cals2html.css', base-uri(.))}" format="els:text"> <xsl:copy-of select="unparsed-text('xslLib:/cals2html.css', 'utf-8')"/> </xsl:result-document>--> </head> <xsl:apply-templates select="$step" mode="xfe:xml2html_finaly"/> </html> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="$step" mode="xfe:xml2html_finaly"/> </xsl:otherwise> </xsl:choose> </xsl:template> <!--================================================================--> <!-- STEP 0 : resolve relation--> <!--================================================================--> <!--Replace the xf:idRef target by the one targeted in the relation--> <xsl:template match="xf:content//*[@xf:idRef[count(key('getRelationByXfId', .)) = 1]]/@xf:idRef" mode="xfe:xml2html_resolveRelation"> <xsl:variable name="relation" select="key('getRelationByXfId', .)" as="element(xf:relation)"/> <xsl:choose> <xsl:when test="$relation/xf:ref/@xf:targetResId"> <!--exclude unresolved relation {query:...}--> <xsl:attribute name="html:href" select="$relation/xf:ref/@xf:targetResId[not(starts-with(., '{'))][not(. = 'NULL')]"/> <xsl:if test="$relation/xf:ref/@idRef"> <xsl:attribute name="{concat('html:', $xfe:dataAttribute.prefix, 'xfe-idRef')}" select="$relation/xf:ref/@idRef"/> </xsl:if> <xsl:if test="$relation/xf:ref/@xf:idRef"> <xsl:attribute name="{concat('html:', $xfe:dataAttribute.prefix, 'xfe-xf_idRef')}" select="$relation/xf:ref/@xf:idRef"/> </xsl:if> </xsl:when> <xsl:otherwise> <!--temp : ancien schéma--> <xsl:attribute name="html:href" select="$relation/xf:ref/@xf:idRef"/> </xsl:otherwise> </xsl:choose> </xsl:template> <!--Make an empty href if the relation is not resolved Unusefull : if the relation is not resolved then don't make a link now, if the element is an externalLink then the href will be initialized later--> <!--<xsl:template match="xf:content//*[@xf:idRef[count(key('getRelationByXfId', .)) != 1]]/@xf:idRef" mode="xfe:xml2html_resolveRelation"> <xsl:message>[WARNING] <xsl:value-of select="count(key('getRelationByXfId', .))"/> relation(s) found for xf:idRef="<xsl:value-of select="."/>". The link will not be resolved</xsl:message> <xsl:attribute name="html:href" select="''"/> </xsl:template>--> <xsl:template match="node() | @*" mode="xfe:xml2html_resolveRelation"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> <!--================================================================--> <!-- STEP 1 : mode xml2html_annotations--> <!--================================================================--> <xsl:template match="*" mode="xfe:xml2html_annotations"> <xsl:param name="rngParentElement" as="element(rng:element)?"/> <xsl:copy> <xsl:apply-templates select="@*" mode="#current"/> <xsl:variable name="rngCurrentElement" as="element(rng:element)?"> <xsl:variable name="classPredicate" as="xs:string+"> <xsl:text>@class='</xsl:text> <xsl:value-of select="@class"/> <xsl:text>'</xsl:text> </xsl:variable> <xsl:choose> <xsl:when test="self::* is root(.)/*"> <xsl:sequence select="rng:getSRNGdataModelFromXpath(concat('/', local-name(.)), $xfe:srng.grammar.normalized)"/> </xsl:when> <xsl:when test="count($rngParentElement) = 0"> <!--nothing : let allowed unvalid elements--> </xsl:when> <xsl:otherwise> <xsl:sequence select="rng:getSRNGdataModelReccurse($rngParentElement, local-name(.), if (@class) then (string-join($classPredicate, '')) else ())"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:if test="count($rngCurrentElement) != 0"> <xsl:attribute name="xfe:srng-define" select="$rngCurrentElement/parent::rng:define/@name"/> <xsl:attribute name="xfe:confElement.xpath" select="xfe:getConfMappingElementsFromXML(., $rngCurrentElement/parent::rng:define/@name)/els:get-xpath(.)"/> </xsl:if> <xsl:apply-templates select="node()" mode="#current"> <xsl:with-param name="rngParentElement" select="$rngCurrentElement"/> </xsl:apply-templates> </xsl:copy> </xsl:template> <xsl:template match="node() | @*" mode="xfe:xml2html_annotations" priority="-1"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> <!--================================================================--> <!-- STEP 2 : mode xml2html_main avec gestion tableaux--> <!--================================================================--> <!--On ajoute le body ici car on va avoir besoin d'une racine pour ajouter le bloc xfe_notes sous le body--> <!--Si la racine n'est pas unique, on ajoute le body, la racine du xml deviendra un div (cf. ci-après), sinon c'est la racine xml qui fera office de body--> <xsl:template match="/*[not($xfe:srng.grammar.rootIsSingle)]" mode="xfe:xml2html_main" priority="1"> <body> <xsl:next-match/> </body> </xsl:template> <!--+ passage en mode addCalsNamespace ou keepAsHtml--> <xsl:template match="*[xfe:getConfMappingElementFromXML(.)/@type = 'cals:table']" mode="xfe:xml2html_main"> <xsl:apply-templates select="." mode="xfe:xml2html_addCalsNamespace"/> </xsl:template> <xsl:template match="*[xfe:getConfMappingElementFromXML(.)/@type = 'html:table']" mode="xfe:xml2html_main"> <xsl:apply-templates select="." mode="xfe:xml2html_keepAsHtml"/> </xsl:template> <!--=================================--> <!--Mode addCalsNamespace--> <!--=================================--> <xsl:template match="*:table | *:tgroup | *:colspec | *:spanspec | *:thead | *:tbody | *:tfoot | *:row | *:TABLE | *:TGROUP | *:COLSPEC | *:SPANSPEC | *:THEAD | *:TBODY | *:TFOOT | *:ROW | *:Table | *:Tgroup | *:Colspec | *:Spanspec | *:Thead | *:Tbody | *:Tfoot | *:Row" mode="xfe:xml2html_addCalsNamespace"> <!--table/titre--> <xsl:element name="cals:{lower-case(local-name())}"> <xsl:for-each select="@*"> <xsl:attribute name="{lower-case(name(.))}" select="."/> </xsl:for-each> <xsl:if test="lower-case(local-name()) = 'table'"> <xsl:call-template name="xfe:addXfeLabel"/> </xsl:if> <xsl:apply-templates mode="#current"/> </xsl:element> </xsl:template> <!--titre de tableau cals : on repasse dans le mode main--> <!--<xsl:template match="*:table/*:titre | *:TABLE/*:TITRE | *:Table/*:Titre " mode="xfe:xml2html_addCalsNamespace"> <xsl:apply-templates select="." mode="xfe:xml2html_main"/> </xsl:template>--> <!--Pour les autres éléments qui ne seraient pas du cals on repasse dans le mode step1--> <xsl:template match="*" mode="xfe:xml2html_addCalsNamespace"> <xsl:apply-templates select="." mode="xfe:xml2html_main"/> </xsl:template> <xsl:template match="*:entry | *:ENTRY | *:Entry" mode="xfe:xml2html_addCalsNamespace"> <xsl:element name="cals:{lower-case(local-name())}"> <xsl:for-each select="@*"> <xsl:attribute name="{lower-case(name(.))}" select="."/> </xsl:for-each> <!--On repasse par le mode normal--> <xsl:apply-templates mode="xfe:xml2html_main"/> </xsl:element> </xsl:template> <!--=================================--> <!--Mode keepAsHtml--> <!--=================================--> <xsl:template match="*:table | *:table//* | *:TABLE | *:TABLE//*" mode="xfe:xml2html_keepAsHtml"> <!--table/titre--> <xsl:element name="{lower-case(local-name())}"> <xsl:copy-of select="@*"/> <xsl:if test="lower-case(local-name(.)) = 'table'"> <xsl:call-template name="xfe:addXfeLabel"/> </xsl:if> <xsl:apply-templates mode="#current"/> </xsl:element> </xsl:template> <xsl:template match="*:td | *:TD | *:th | *:TH | *:caption | *:CAPTION" mode="xfe:xml2html_keepAsHtml" priority="1"> <xsl:element name="{lower-case(local-name())}"> <xsl:copy-of select="@*"/> <!--On repasse par le mode normal--> <xsl:apply-templates mode="xfe:xml2html_main"/> </xsl:element> </xsl:template> <!--=================================--> <!-- Mode xfe:xml2html_main default --> <!--=================================--> <!--DEBUG--> <!--<xsl:template match="e"> <xsl:variable name="e.dataModel" select="rng:getSRNGdataModelFromXmlElement(., $srng.grammar)" as="element(rng:element)"/> <xsl:variable name="e.parent.dataModel" select="rng:getSRNGdataModelFromXmlElement(./parent::*, $srng.grammar)" as="element(rng:element)"/> <parentDataModel> <xsl:copy-of select="$e.parent.dataModel"/> </parentDataModel> <DataModel> <xsl:copy-of select="$e.dataModel"/> </DataModel> <xsl:variable name="ref" select="$e.parent.dataModel//rng:ref[rng:getDefine(.)/rng:element is $e.dataModel]" as="element(rng:ref)"/> <inline><xsl:value-of select="exists($ref/ancestor::rng:interleave/rng:text)"/></inline> <isInline><xsl:value-of select="rng:isInline($e.dataModel, $e.parent.dataModel)"/></isInline> <!-\-<xsl:message><xsl:value-of select="local-name()"/> : <xsl:value-of select="xf:getHtmlElementName(.)"/></xsl:message>-\-> </xsl:template>--> <xsl:template match="*[$xfe:conf.hasSchema][count(@xfe:srng-define) = 0]" mode="xfe:xml2html_main" priority="1"> <xsl:variable name="msg" as="xs:string*"> <xsl:text>Element <</xsl:text> <xsl:value-of select="local-name(.)"/> <xsl:if test="@*"><xsl:for-each select="@*"><xsl:value-of select="concat(' ', name(), '="', ., '"')"/></xsl:for-each></xsl:if> <xsl:text>> not expected here by the schema</xsl:text> </xsl:variable> <xsl:choose> <xsl:when test="$xfe:allowUnValidXML"> <div class="xfe-error" style="background-color:red; color:white; padding:0.5em; font-family: monospace;"> <h3 style="margin-bottom:0">ERROR : <xsl:value-of select="$msg"/></h3> <p>xpath : <xsl:value-of select="els:get-xpath(.)"/><br/>xfe:srng.uri : <xsl:value-of select="$xfe:srng.uri"/></p> <div> <xsl:apply-templates select="." mode="els:xml2simpleHtml"/> </div> </div> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="level" select="'warning'"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[WARNING] <xsl:value-of select="$msg"/></xsl:with-param> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="level" select="'fatal'"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[FATAL] <xsl:value-of select="$msg"/></xsl:with-param> </xsl:call-template> <xsl:message terminate="yes"/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="*[ancestor::*][not($xfe:conf.hasSchema)][count(xfe:getConfMappingElementFromXML(.)) = 0]" mode="xfe:xml2html_main" priority="1"> <xsl:variable name="msg" as="xs:string*"> <xsl:text>Element <</xsl:text> <xsl:value-of select="local-name(.)"/> <xsl:if test="@*"><xsl:for-each select="@*"><xsl:value-of select="concat(' ', name(), '="', ., '"')"/></xsl:for-each></xsl:if> <xsl:text>> is not mapped in the conf. </xsl:text> <xsl:value-of select="els:get-xpath(.)"/> </xsl:variable> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="level" select="'warning'"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[WARNING] <xsl:value-of select="$msg"/> (it might be a namespace prefix problem, because evaluation is based on the root default namespace)</xsl:with-param> </xsl:call-template> <h3 class="xfe-error" style="margin-bottom:0; background-color:red; color:white; padding:0.5em; font-family: monospace;">ERROR : <xsl:value-of select="$msg" separator=""/></h3> <xsl:apply-templates mode="#current"/> </xsl:template> <xsl:template match="*" mode="xfe:xml2html_main"> <xsl:variable name="self" select="self::*" as="element()"/> <xsl:variable name="confMappingElement" select="xfe:getConfMappingElementFromXML(.)" as="element()?"/> <xsl:variable name="isXMLrootElement" select="not(ancestor::*)" as="xs:boolean"/> <xsl:if test="$confMappingElement/@error"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'error'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description"><xsl:value-of select="$confMappingElement/@error"/> (<xsl:value-of select="els:get-xpath(.)"/>)</xsl:with-param> </xsl:call-template> </xsl:if> <xsl:variable name="isVoid" select="normalize-space($confMappingElement/@html-name) = 'void'" as="xs:boolean"/> <xsl:variable name="e.dataModel" select="if (not($isVoid) and $xfe:conf.hasSchema) then (rng:getSRNGdataModelFromXmlElement(., $xfe:srng.grammar.normalized)) else ()" as="element(rng:element)?"/> <xsl:variable name="htmlElementName" as="xs:string?"> <xsl:choose> <xsl:when test="$isVoid"> <!--ne pas sortir d'élément ici--> </xsl:when> <!--l'élément est surchargé dans la conf--> <xsl:when test="normalize-space($confMappingElement/@html-name) != ''"> <xsl:value-of select="$confMappingElement/@html-name"/> </xsl:when> <!--La racine sera toujours un div ou un body --> <xsl:when test="$isXMLrootElement"> <xsl:choose> <xsl:when test="$xfe:srng.grammar.rootIsSingle"> <xsl:text>body</xsl:text> </xsl:when> <xsl:otherwise> <xsl:text>div</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:when> <xsl:when test="$xfe:srng.is-xhtml"> <xsl:value-of select="local-name(.)"/> </xsl:when> <xsl:when test="not($xfe:conf.hasSchema)"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'error'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[FATAL] Unable to find the html name for <xsl:value-of select="els:displayNode(.)"/></xsl:with-param> </xsl:call-template> <xsl:message terminate="yes"/> </xsl:when> <xsl:otherwise> <!--default inline or block ? we need to check the element data-model in srng schema--> <!--<xsl:variable name="e.dataModel" select="rng:getSRNGdataModelFromXmlElement(., $xfe:srng.grammar.normalized)" as="element(rng:element)"/>--> <xsl:variable name="e.parent.dataModel" select="rng:getSRNGdataModelFromXmlElement(parent::*, $xfe:srng.grammar.normalized)" as="element(rng:element)"/> <!--<xsl:value-of select="els:displayNode($e.dataModel/parent::rng:define)"/>--> <xsl:choose> <xsl:when test="rng:isInline($e.dataModel, $e.parent.dataModel)"> <xsl:text>span</xsl:text> </xsl:when> <xsl:otherwise> <xsl:text>div</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:choose> <xsl:when test="$isVoid"> <xsl:apply-templates mode="#current"/> </xsl:when> <xsl:otherwise> <xsl:element name="{$htmlElementName}"> <xsl:variable name="xmlNameAsClass" select="not(matches($confMappingElement/@html-xmlNameAsClass, '(false|0)'))" as="xs:boolean"/> <xsl:variable name="class" as="xs:string*"> <xsl:if test="$xmlNameAsClass and not($xfe:srng.is-xhtml)"> <xsl:value-of select="local-name()"/> </xsl:if> <xsl:if test="$confMappingElement/@html-addClass != ''"> <xsl:value-of select="$confMappingElement/@html-addClass"/> </xsl:if> <xsl:if test="$xfe:srng.is-xhtml and @class and not($confMappingElement/@html-ignoreXmlAttributes = 'class')"> <xsl:value-of select="@class"/> </xsl:if> </xsl:variable> <xsl:call-template name="xfe:addXfeLabel"> <xsl:with-param name="confMappingElement" select="$confMappingElement" as="element()?"/> </xsl:call-template> <xsl:if test="string-join($class, ' ') != ''"> <xsl:attribute name="class" select="string-join($class, ' ')"/> </xsl:if> <xsl:if test="starts-with($confMappingElement/@type, 'xfe:list(')"> <xsl:choose> <xsl:when test="matches($confMappingElement/@type, 'xfe:list\(.*?\)')"> <xsl:variable name="listTypeValue.xpath" select="replace($confMappingElement/@type, '^xfe:list\((.*?)\)$', '$1')" as="xs:string"/> <xsl:attribute name="{concat($xfe:dataAttribute.prefix, 'xfe-listType')}"> <!--<xsl:message>evaluate(<xsl:value-of select="$listTypeValue.xpath"/>, .)=<xsl:value-of select="els:evaluate-xpath($listTypeValue.xpath, .)"/></xsl:message>--> <xsl:value-of select="normalize-space(els:evaluate-xpath($listTypeValue.xpath, .))"/> </xsl:attribute> </xsl:when> <xsl:otherwise> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'error'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[ERROR] @type xfe:list doit être de la forme xfe:list(expressionXpath)</xsl:with-param> </xsl:call-template> <xsl:message terminate="yes"/> </xsl:otherwise> </xsl:choose> </xsl:if> <xsl:variable name="htmlAttributes" select="$confMappingElement/@*[starts-with(local-name(.), 'html-attribute-')]" as="attribute()*"/> <xsl:if test="count($htmlAttributes) != 0"> <xsl:for-each select="$htmlAttributes"> <xsl:attribute name="{substring-after(local-name(.), 'html-attribute-')}" select="els:evaluate-xpath(., $self)"/> </xsl:for-each> </xsl:if> <xsl:choose> <!--FIXME : ce choose pourrait être mis plus haut mais il faudra gérer les impact sur le html.rng et sur la css, pour l'instant on laisse ici--> <!--Common case :--> <xsl:when test="not($isXMLrootElement and $xfe:srng.grammar.rootIsSingle)"> <xsl:for-each select="@* except (@xfe:*|@xf:*|@html:*|(@id|@ID|@Id)[1])"> <xsl:if test="not(name() = tokenize($confMappingElement/@html-ignoreXmlAttributes, '\s+')) and not($xfe:srng.is-xhtml and name()= 'class')"> <xsl:attribute name="{concat($xfe:dataXmlAttribute.prefix, local-name(.))}"> <xsl:choose> <!-- Convert canonical boolean attribute values to integer values (0 / 1) because TinyMCE doesn't handle true / false --> <xsl:when test="rng:getAttributeDataType($e.dataModel,name(.)) = 'boolean'"> <xsl:value-of select="els:convertAtomicValueToIntegerBooleanValue(.)"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="."/> </xsl:otherwise> </xsl:choose> </xsl:attribute> </xsl:if> </xsl:for-each> <!--Empty href attribute for external links--> <xsl:if test="starts-with($confMappingElement/@type, 'xfe:externalLinkType') and $htmlElementName = 'a'"> <xsl:attribute name="href" select="''"/> </xsl:if> <!--This href will be override by the resolved relation (in case it has one) that has been calculated before with @html:href--> <xsl:for-each select="@html:*"> <xsl:attribute name="{local-name(.)}" select="."/> </xsl:for-each> <!--<xsl:for-each select="@xf:refType"> <xsl:attribute name="{concat($dataXmlAttribute.prefix, 'xf_', local-name(.))}" select="."/> </xsl:for-each>--> </xsl:when> <!--From here we are on the single root element--> <xsl:otherwise> <xsl:if test="$xfe:conf.hasSchema"> <xsl:if test="@* except @xfe:*"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'error'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[ERROR] the root element of a single root grammar should not have attributes because the editor will not deal with them : remove attribute(s) <xsl:value-of select="(@* except @xfe:*)/name(.)" separator=", "/></xsl:with-param> </xsl:call-template> </xsl:if> <xsl:if test="count($confMappingElement)"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'error'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[ERROR] Conf mapping element on the root element of a single root grammar will be ignored</xsl:with-param> </xsl:call-template> </xsl:if> </xsl:if> </xsl:otherwise> </xsl:choose> <xsl:if test="@id | @ID | @Id"> <xsl:attribute name="id" select="(@id | @ID | @Id)[1]"/> </xsl:if> <xsl:if test="normalize-space($confMappingElement/@type) = 'xfe:inlineNote'"> <xsl:attribute name="xfe_type" select="$confMappingElement/@type"/> </xsl:if> <xsl:call-template name="xfe:revisionPiTohtml"/> <!--<xsl:apply-templates mode="#current"/>--> </xsl:element> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template name="xfe:addXfeLabel"> <xsl:param name="confMappingElement" select="xfe:getConfMappingElementFromXML(.)" as="element()?"/> <xsl:if test="$xfe:addXfeLabel"> <!--<xsl:attribute name="{$dataAttribute.prefix}xfe-label" ... Error with saxon9.7, cf. http://markmail.org/thread/xoajcp6uemrmkp6q --> <xsl:attribute name="{concat($xfe:dataAttribute.prefix, 'xfe-label')}" select="($confMappingElement/@label, local-name(.))[1]"/> </xsl:if> </xsl:template> <xsl:template name="xfe:revisionPiTohtml"> <xsl:for-each-group select="node()" group-starting-with="processing-instruction('xfe_del_start')"> <xsl:choose> <xsl:when test="current-group()[1]/self::processing-instruction('xfe_del_start')"> <xsl:variable name="piStart" select="current-group()[1]" as="processing-instruction()"/> <xsl:for-each-group select="current-group()" group-ending-with="processing-instruction('xfe_del_end')"> <xsl:choose> <xsl:when test="current-group()[last()]/self::processing-instruction('xfe_del_end')"> <del> <xsl:copy-of select="els:pseudoAttributes2xml($piStart, $els:dquot)"/> <xsl:apply-templates select="current-group()" mode="xfe:xml2html_main"/> </del> </xsl:when> <xsl:otherwise> <xsl:call-template name="xfe:insPiTohtml"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:when> <xsl:otherwise> <xsl:call-template name="xfe:insPiTohtml"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:template> <xsl:template name="xfe:insPiTohtml"> <xsl:for-each-group select="current-group()" group-starting-with="processing-instruction('xfe_ins_start')"> <xsl:choose> <xsl:when test="current-group()[1]/self::processing-instruction('xfe_ins_start')"> <xsl:variable name="piStart" select="current-group()[1]" as="processing-instruction()"/> <xsl:for-each-group select="current-group()" group-ending-with="processing-instruction('xfe_ins_end')"> <xsl:choose> <xsl:when test="current-group()[last()]/self::processing-instruction('xfe_ins_end')"> <ins> <xsl:copy-of select="els:pseudoAttributes2xml($piStart, $els:dquot)"/> <xsl:apply-templates select="current-group()" mode="xfe:xml2html_main"/> </ins> </xsl:when> <xsl:otherwise> <xsl:call-template name="xfe:commentPiTohtml"/> <!--<xsl:apply-templates select="current-group()" mode="xfe:xml2html_main"/>--> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:when> <xsl:otherwise> <xsl:call-template name="xfe:commentPiTohtml"/> <!--<xsl:apply-templates select="current-group()" mode="xfe:xml2html_main"/>--> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:template> <xsl:template name="xfe:commentPiTohtml"> <xsl:for-each-group select="current-group()" group-starting-with="processing-instruction('xfe_comment_start')"> <xsl:choose> <xsl:when test="current-group()[1]/self::processing-instruction('xfe_comment_start')"> <xsl:variable name="piStart" select="current-group()[1]" as="processing-instruction()"/> <xsl:for-each-group select="current-group()" group-ending-with="processing-instruction('xfe_comment_end')"> <xsl:choose> <xsl:when test="current-group()[last()]/self::processing-instruction('xfe_comment_end')"> <span class="tinyMce_annotation"> <xsl:copy-of select="els:pseudoAttributes2xml($piStart, $els:dquot)"/> <xsl:apply-templates select="current-group()" mode="xfe:xml2html_main"/> </span> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="current-group()" mode="xfe:xml2html_main"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="current-group()" mode="xfe:xml2html_main"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:template> <!--<xsl:template match="processing-instruction('xfe_comment')" mode="xfe:xml2html_main"> <span class="tinyMce_annotation"> <xsl:copy-of select="els:pseudoAttributes2xml(., $els:dquot)"/> </span> </xsl:template>--> <!--================================================================--> <!-- STEP 3 : xslLib:cals2html --> <!--================================================================--> <!--cf. xslLib:/cals2html.xsl --> <!--Override cals2html mode for xfe annotation attributes--> <xsl:template match="@xfe:*" mode="xslLib:cals2html.attributes"/> <!--Consider @security attribute is never usefull for XFE--> <xsl:template match="@security" mode="xslLib:cals2html.attributes"/> <xsl:template match="@*[name() = concat($xfe:dataAttribute.prefix, 'xfe-label')]" mode="xslLib:cals2html.attributes"> <xsl:copy-of select="."/> </xsl:template> <!--================================================================--> <!-- STEP 4 : moveInlineNotes --> <!--================================================================--> <!--suppression du contenu de la note en ligne qui est mise dans un div "xfe_notes" plus bas--> <!--On vide la note en line de son contenu--> <xsl:template match="*[@xfe_type = 'xfe:inlineNote']" mode="xfe:xml2html_step3_moveInlineNotes"> <xsl:copy> <xsl:apply-templates select="@* except @xfe_type" mode="#current"/> <xsl:attribute name="href" select="concat('#' , xfe:generateInlineNoteId(.))"/> </xsl:copy> </xsl:template> <!--Ajout d'un conteneur pour les notes après la racine--> <xsl:template match="/html:body[$xfe:conf.normalized//*[@type = 'xfe:inlineNote']]" mode="xfe:xml2html_step3_moveInlineNotes"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[INFO] Adding block "xfe_notes" inside html body</xsl:with-param> </xsl:call-template> <xsl:copy> <xsl:apply-templates select="@* | node()" mode="#current"/> <div class="xfe_notes"> <xsl:apply-templates select="//*[@xfe_type = 'xfe:inlineNote']" mode="step3_copyInlineNoteContent"/> </div> </xsl:copy> </xsl:template> <!--Déplacement des notes dans ce conteneur--> <xsl:template match="*[@xfe_type = 'xfe:inlineNote']" mode="step3_copyInlineNoteContent"> <div class="xfe_note" id="{xfe:generateInlineNoteId(.)}"> <xsl:apply-templates select="node()" mode="#current"/> </div> </xsl:template> <xsl:template match="node() | @*" mode="xfe:xml2html_step3_moveInlineNotes step3_copyInlineNoteContent"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> <xsl:function name="xfe:generateInlineNoteId" as="xs:string"> <xsl:param name="noteRef" as="element()"/> <xsl:sequence select="concat('xfe-note_', count($noteRef/preceding::*[@xfe_type = 'xfe:inlineNote']) + 1)"/> </xsl:function> <!--================================================================--> <!-- STEP 5 : xml2html_customizeCals2html --> <!--================================================================--> <!-- cf xslLib:/xslLib/cals2html.xsl --> <!-- On surcharge la transfo de la librairie --> <xsl:template match="html:div[els:hasClass(., 'cals_table')]/@class" mode="xslLib:xml2html_customizeCals2html"> <xsl:attribute name="class" select="'blocTableau'"/> <xsl:attribute name="data-xfe-label" select="'blocTableau'"/> </xsl:template> <!--FIXME : mettre 1 param dans cals2html serait une autre solution--> <xsl:template match="@*[starts-with(name(), 'data-cals-')]" mode="xslLib:xml2html_customizeCals2html"> <xsl:attribute name="{concat($xfe:dataXmlAttribute.prefix, substring-after(name(.), 'data-cals-'))}" select="."/> </xsl:template> <xsl:template match="node() | @*" mode="xslLib:xml2html_customizeCals2html"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> <!--================================================================--> <!-- STEP 5 : xfe:xml2html_finaly --> <!--================================================================--> <!--FE-151 : FIXME trouver un mécanisme plus propre, on le mets ici car urgence--> <!-- => On rajoute simplement le contenu de $xfe:media.url.path à la valeur de @src qui devrait être du type EFL_TEE_uiCommentaire/chaineXML/XXXX.jpg--> <xsl:template match="html:img/@src" mode="xfe:xml2html_finaly"> <xsl:attribute name="{local-name(.)}" select="concat($xfe:media.url.path, .)"/> </xsl:template> <!--Delete xfe attributes which have been added during processing--> <xsl:template match="@xfe:*" mode="xfe:xml2html_finaly"/> <xsl:template match="node() | @*" mode="xfe:xml2html_finaly"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:xf="http://www.lefebvre-sarrut.eu/ns/xmlfirst" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" xmlns:xfe="http://www.lefebvre-sarrut.eu/ns/xmlfirst/xmlEditor" xmlns:html="http://www.w3.org/1999/xhtml" exclude-result-prefixes="#all" version="3.0"> <xsl:import href="xslLib:/xslLib/rng-common.xsl"/> <!-- Librairie utilitaire lié aux logs ELS --> <xsl:import href="xslLib:/xslLib/els-log.xsl"/> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>Common function and templates for XFE</xd:p> </xd:desc> </xd:doc> <xsl:key name="getRelationByXfId" match="xf:relation" use="@xf:id"/> <!--FE-68 : This debug parameter can be used to desactivate logging to file system when this XSLT is imported : XTDE1480: Cannot execute xsl:result-document while evaluating variable--> <xsl:param name="xfe:debug" select="true()" as="xs:boolean"/> <!--ECM path for externalLink to editorialEntity--> <xsl:param name="xfe:ecm.ee.url.path" select="'/#/editorialEntity/'" as="xs:string"/> <xsl:param name="xfe:media.url.path" select="'/api/media/original/'" as="xs:string"/> <!--Par défaut les log sont écrits à côté du xml--> <xsl:param name="LOG.URI" select="resolve-uri('log', base-uri(.))" as="xs:string"/> <xsl:variable name="log.uri" select="if(ends-with($LOG.URI, '/')) then ($LOG.URI) else(concat($LOG.URI, '/'))" as="xs:string"/> <!--Overriding css path and name of the conf file is possible--> <xsl:param name="xfe:css.name" as="xs:string?"/> <xsl:param name="xfe:css.path" as="xs:string?"/> <!--log level code for logging --> <xsl:param name="els:log.level.code" select="'xfe'" as="xs:string"/> <!--configuration file for XFE--> <xsl:param name="xfe:conf.uri" select="resolve-uri('xfe-conf.xml', base-uri(/))" as="xs:string"/> <xsl:variable name="xfe:conf.generate-missing-mapping-from-schema" select="false()" as="xs:boolean"/> <xsl:variable name="xfe:conf" as="element()"> <xsl:choose> <xsl:when test="doc-available($xfe:conf.uri)"> <xsl:sequence select="document($xfe:conf.uri)/*"/> </xsl:when> <xsl:otherwise> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'fatal'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">document <xsl:value-of select="$xfe:conf.uri"/> is not available</xsl:with-param> </xsl:call-template> <xsl:message terminate="yes"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="xfe:conf.resolved.get-recursive-imports" as="document-node()"> <xsl:document> <xsl:apply-templates select="$xfe:conf" mode="xfe:conf.resolved.get-recursive-imports"/> </xsl:document> </xsl:variable> <xsl:variable name="xfe:conf.resolved" as="document-node()"> <xsl:document> <xsl:apply-templates select="$xfe:conf.resolved.get-recursive-imports" mode="xfe:resolve-conf"/> </xsl:document> </xsl:variable> <xsl:variable name="xfe:conf.hasSchema" select="exists($xfe:conf/*:srngXmlmodel/@href)" as="xs:boolean"/> <xsl:variable name="xfe:srng.href" select="$xfe:conf/*:srngXmlmodel/@href" as="xs:anyURI?"/> <xsl:variable name="xfe:srng.uri" select="resolve-uri($xfe:srng.href, $xfe:conf.uri)" as="xs:anyURI?"/> <xsl:variable name="xfe:srng" as="document-node()?"> <xsl:if test="$xfe:conf.hasSchema"> <xsl:choose> <xsl:when test="doc-available($xfe:srng.uri)"> <xsl:sequence select="document($xfe:srng.uri)"/> </xsl:when> <xsl:otherwise> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'fatal'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">document <xsl:value-of select="$xfe:srng.uri"/> is not available</xsl:with-param> </xsl:call-template> <xsl:message terminate="yes"/> </xsl:otherwise> </xsl:choose> </xsl:if> </xsl:variable> <xsl:variable name="xfe:srng.normalized" as="document-node()?"> <xsl:if test="$xfe:conf.hasSchema"> <xsl:document> <xsl:apply-templates select="$xfe:srng" mode="xfe:srng_duplicateDefineByAttributeValue"/> </xsl:document> </xsl:if> </xsl:variable> <xsl:variable name="xfe:srng.grammar.normalized" select="$xfe:srng.normalized/rng:grammar" as="element(rng:grammar)?"/> <xsl:variable name="xfe:conf.normalized" as="element()?"> <xsl:variable name="step" as="document-node()"> <xsl:document> <xsl:apply-templates select="$xfe:conf.resolved" mode="normalizeConf.step1"/> </xsl:document> </xsl:variable> <xsl:variable name="step" as="document-node()"> <xsl:document> <xsl:apply-templates select="$step" mode="normalizeConf.step2"/> </xsl:document> </xsl:variable> <xsl:choose> <xsl:when test="$xfe:conf.generate-missing-mapping-from-schema"> <xsl:apply-templates select="$step" mode="normalizeConf.step3"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="$step/*"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="xfe:srng.grammar.rootIsSingle" select="if($xfe:conf.hasSchema) then(rng:rootIsSingle($xfe:srng.grammar.normalized)) else(true())" as="xs:boolean"/> <xsl:variable name="xfe:srng.is-xhtml" select="($xfe:conf/*:srngXmlmodel/@is-xhtml, false())[1]" as="xs:boolean"/> <xsl:variable name="xfe:dataAttribute.prefix" select="'data-'" as="xs:string"/> <xsl:variable name="xfe:dataXmlAttribute.prefix" select="concat($xfe:dataAttribute.prefix, 'xml-')" as="xs:string"/> <xsl:variable name="xfe:dataXfeAttribute.prefix" select="concat($xfe:dataAttribute.prefix, 'xfe-')" as="xs:string"/> <!--=================================================--> <!--MODE xfe:conf.resolved.get-recursive-imports--> <!--=================================================--> <xsl:template match="/*:conf" mode="xfe:conf.resolved.get-recursive-imports"> <xsl:param name="rel-uri" as="xs:string?"/> <xsl:variable name="uri" select="document-uri(/)" as="xs:anyURI"/> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:if test="not(empty($rel-uri))"> <xsl:attribute name="xml:base" select="$rel-uri"/> </xsl:if> <xsl:apply-templates mode="#current"> <xsl:with-param name="caller.uri" select="$uri" tunnel="yes"/> </xsl:apply-templates> </xsl:copy> </xsl:template> <xsl:template match="*:import" mode="xfe:conf.resolved.get-recursive-imports"> <xsl:param name="caller.uri" as="xs:anyURI" tunnel="yes"/> <xsl:variable name="this.uri" select="resolve-uri(@href,base-uri(.))" as="xs:anyURI"/> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:if test="$caller.uri != $this.uri"> <xsl:choose> <xsl:when test="doc-available($this.uri)"> <xsl:apply-templates select="document($this.uri)/*" mode="#current"> <xsl:with-param name="rel-uri" select="@href"/> </xsl:apply-templates> </xsl:when> <xsl:otherwise> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'fatal'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[FATAL] import href="<xsl:value-of select="@href"/>" is not available in <xsl:value-of select="base-uri(.)"/></xsl:with-param> </xsl:call-template> <xsl:message terminate="yes"/> </xsl:otherwise> </xsl:choose> </xsl:if> </xsl:copy> </xsl:template> <!--copy template--> <xsl:template match="node() | @*" mode="xfe:conf.resolved.get-recursive-imports"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> <!--=================================================--> <!--MODE xfe:normalizeConf--> <!--=================================================--> <!--Starting resolving conf at document-node()--> <xsl:template match="/" mode="xfe:resolve-conf"> <xsl:choose> <xsl:when test="*:conf/*:import"> <xsl:call-template name="xfe:resolve-conf"> <xsl:with-param name="conf" select="*:conf" as="element()"/> <xsl:with-param name="level" select="count(descendant::*:import)" as="xs:integer"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:sequence select="."/> </xsl:otherwise> </xsl:choose> </xsl:template> <!--Recursiv template to resolve conf step by step, starting at deeper level and getting to 1st level of nested conf--> <xsl:template name="xfe:resolve-conf"> <xsl:param name="conf" required="yes" as="element()"/> <xsl:param name="level" required="yes" as="xs:integer"/> <xsl:choose> <xsl:when test="$level = 0"> <xsl:sequence select="$conf"/> </xsl:when> <xsl:otherwise> <xsl:variable name="conf.level-n" as="element()"> <xsl:apply-templates select="$conf" mode="xfe:resolve-conf"> <xsl:with-param name="level" select="$level" as="xs:integer" tunnel="yes"/> </xsl:apply-templates> </xsl:variable> <xsl:call-template name="xfe:resolve-conf"> <xsl:with-param name="conf" select="$conf.level-n" as="element()"/> <xsl:with-param name="level" select="$level - 1" as="xs:integer"/> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:template> <!--From here the conf resolution works with elements (no document-node) after being called by the recursiv template name="xfe:resolve-conf"--> <xsl:template match="*:conf" mode="xfe:resolve-conf"> <xsl:param name="level" as="xs:integer" tunnel="yes"/> <xsl:choose> <xsl:when test="count($level) = 0"> <xsl:next-match/> </xsl:when> <xsl:when test="count(ancestor::*:import) = $level -1"> <xsl:variable name="importedConf" select="*:import/*:conf" as="element()"/> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:choose> <xsl:when test="*:srngXmlmodel"> <xsl:apply-templates select="*:srngXmlmodel" mode="#current"/> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="$importedConf/*:srngXmlmodel" mode="xfe:resolve-conf.copy-importedConf"/> </xsl:otherwise> </xsl:choose> <xsl:choose> <xsl:when test="*:title"> <xsl:apply-templates select="*:title" mode="#current"/> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="$importedConf/*:title" mode="xfe:resolve-conf.copy-importedConf"/> </xsl:otherwise> </xsl:choose> <xsl:choose> <xsl:when test="*:css"> <xsl:apply-templates select="*:css" mode="#current"/> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="$importedConf/*:css" mode="xfe:resolve-conf.copy-importedConf"/> </xsl:otherwise> </xsl:choose> <xsl:choose> <xsl:when test="*:mapping"> <xsl:apply-templates select="*:mapping" mode="#current"> <xsl:with-param name="importedConf" select="$importedConf" as="element()"/> </xsl:apply-templates> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="$importedConf/*:mapping" mode="xfe:resolve-conf.copy-importedConf"/> </xsl:otherwise> </xsl:choose> </xsl:copy> </xsl:when> <xsl:otherwise> <xsl:next-match/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="*:mapping" mode="xfe:resolve-conf"> <xsl:param name="importedConf" as="element()?"/> <xsl:variable name="self" select="." as="element()"/> <xsl:copy> <xsl:copy-of select="@*"/> <!--copy every child (*:element) of the original conf--> <xsl:apply-templates mode="#current"/> <!--copy every child (*:element) of the imported conf except those which are already defined in the original conf--> <xsl:for-each select="$importedConf/*:mapping/*:element"> <xsl:if test="not(concat(@xpath, '_', @xpath-filter) = $self/*:element/concat(@xpath, '_', @xpath-filter))"> <xsl:apply-templates select="." mode="xfe:resolve-conf.copy-importedConf"/> </xsl:if> </xsl:for-each> </xsl:copy> </xsl:template> <!--default copy--> <xsl:template match="node() | @*" mode="xfe:resolve-conf xfe:resolve-conf.copy-importedConf" priority="-1"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> <!--===== STEP 1 =====--> <!--Gestion des @type--> <!--CALS Tables--> <xsl:template match="*:element[@type = 'cals:table']" mode="normalizeConf.step1"> <xsl:variable name="element.name" select="tokenize(@xpath, '/')[last()]" as="xs:string"/> <xsl:variable name="nameCase" select="xfe:getTableCasePattern($element.name)" as="xs:string"/> <!--on estime que la casse sera la même sur tous les éléments du langage cals--> <!--<xsl:copy-of select="@xpath-filter"/> FIXME : ne s'applique pas au même nœud--> <xsl:copy> <xsl:copy-of select="@*"/> <!--FIXME : schematron : interdire @html-name/@html-addClass sur les table, FE-124 => car Tiny est configuré pour (?)--> <xsl:attribute name="html-name" select="'div'"/> <xsl:attribute name="html-addClass" select="'blocTableau'"/> <xsl:attribute name="label" select="(@label, xfe:getNameFromXpath(.))[1]"/> <xsl:attribute name="html-xmlNameAsClass" select="'false'"/> </xsl:copy> <element xpath="{@xpath}/{xfe:apply-case('tgroup', $nameCase)}" html-name="table" type="cals:tgroup" html-xmlNameAsClass="false"/> <element xpath="{@xpath}/tgroup/{xfe:apply-case('colspec', $nameCase)}" html-name="col" type="cals:colspec" html-xmlNameAsClass="false"/> <!--<element xpath="{@xpath}/{xfe:conditional-upper-case('spanspec', $nameCase)}" html-name="?"/>--> <element xpath="{@xpath}/{xfe:apply-case('tgroup', $nameCase)}/{xfe:apply-case('thead', $nameCase)}" html-name="thead" type="cals:thead" html-xmlNameAsClass="false"/> <element xpath="{@xpath}/{xfe:apply-case('tgroup', $nameCase)}/{xfe:apply-case('tbody', $nameCase)}" html-name="tbody" type="cals:tbody" html-xmlNameAsClass="false"/> <element xpath="{@xpath}/{xfe:apply-case('tgroup', $nameCase)}/{xfe:apply-case('tfoot', $nameCase)}" html-name="tfoot" type="cals:tfoot" html-xmlNameAsClass="false"/> <element xpath="{@xpath}/{xfe:apply-case('tgroup', $nameCase)}//{xfe:apply-case('row', $nameCase)}" html-name="tr" type="cals:row" html-xmlNameAsClass="false"/> <element xpath="{@xpath}/{xfe:apply-case('tgroup', $nameCase)}/{xfe:apply-case('tbody', $nameCase)}/{xfe:apply-case('row', $nameCase)}/{xfe:apply-case('entry', $nameCase)}" html-name="td" type="cals:entry" html-xmlNameAsClass="false"/> <element xpath="{@xpath}/{xfe:apply-case('tgroup', $nameCase)}/{xfe:apply-case('thead', $nameCase)}/{xfe:apply-case('row', $nameCase)}/{xfe:apply-case('entry', $nameCase)}" html-name="th" type="cals:entry" html-xmlNameAsClass="false"/> <!--xpath-filter="ancestor::thead" => génère ambiguité sur élément de surcharge, peut être ancestor::*:thead ?--> </xsl:template> <!--HTML Tables--> <xsl:template match="*:element[@type = 'html:table']" mode="normalizeConf.step1"> <xsl:variable name="element.name" select="tokenize(@xpath, '/')[last()]" as="xs:string"/> <xsl:variable name="nameCase" select="xfe:getTableCasePattern($element.name)" as="xs:string"/> <!--on estime que la casse sera la même sur tous les éléments du langage cals--> <!--<xsl:copy-of select="@xpath-filter"/> FIXME : ne s'applique pas au même nœud--> <xsl:copy> <xsl:attribute name="html-name" select="'table'"/> <xsl:attribute name="html-xmlNameAsClass" select="'false'"/> <xsl:copy-of select="@*"/> </xsl:copy> <element xpath="{@xpath}/{xfe:apply-case('caption', $nameCase)}" html-name="caption" type="html:caption" html-xmlNameAsClass="false"/> <element xpath="{@xpath}/{xfe:apply-case('col', $nameCase)}" html-name="col" type="html:col" html-xmlNameAsClass="false"/> <element xpath="{@xpath}/{xfe:apply-case('colgroup', $nameCase)}" html-name="colgroup" type="html:colgroup" html-xmlNameAsClass="false"/> <element xpath="{@xpath}/{xfe:apply-case('thead', $nameCase)}" html-name="thead" type="html:thead" html-xmlNameAsClass="false"/> <element xpath="{@xpath}/{xfe:apply-case('tbody', $nameCase)}" html-name="tbody" type="html:tbody" html-xmlNameAsClass="false"/> <element xpath="{@xpath}/{xfe:apply-case('tfoot', $nameCase)}" html-name="tfoot" type="html:tfoot" html-xmlNameAsClass="false"/> <element xpath="{@xpath}/{xfe:apply-case('tr', $nameCase)}" html-name="tr" type="html:tr" html-xmlNameAsClass="false"/> <!--FIXME : attention le xpath table/td devient faux... et pourtant ça marche ???--> <element xpath="{@xpath}/{xfe:apply-case('td', $nameCase)}" html-name="td" type="html:td" html-xmlNameAsClass="false"/> <element xpath="{@xpath}/{xfe:apply-case('th', $nameCase)}" html-name="th" type="html:th" html-xmlNameAsClass="false"/> </xsl:template> <xsl:template match="*:element[starts-with(@type, 'xfe:title-')]" mode="normalizeConf.step1"> <xsl:variable name="level" select="substring-after(@type, 'xfe:title-')" as="xs:string"/> <xsl:copy> <xsl:apply-templates select="@*" mode="#current"/> <!--on force certains attributs--> <!--cf. schematron conf--> <xsl:attribute name="html-addClass" select="normalize-space(concat('xfe_title-', $level, ' ', @html-addClass))"/> <!--Don't set @html-name : it could be set to h1, h2, etc. or div, depending on the xml--> </xsl:copy> </xsl:template> <xsl:template match="*:element[starts-with(@type, 'xfe:list(')]" mode="normalizeConf.step1"> <xsl:copy> <xsl:attribute name="html-name" select="'ul'"/> <!--default value, can be overrided--> <xsl:apply-templates select="@* | node()" mode="#current"/> </xsl:copy> </xsl:template> <xsl:template match="*:element[starts-with(@type, 'xfe:externalLinkType')]" mode="normalizeConf.step1"> <xsl:copy> <!--<xsl:apply-templates select="@*" mode="#current"/>--> <!--on force certains attributs--> <xsl:attribute name="html-name" select="'a'"/> <!--FIXME : pour éviter trop d'impacts, on conserve html-name si spécifié--> <xsl:apply-templates select="@*" mode="#current"/> </xsl:copy> </xsl:template> <xsl:template match="*:element[@type = 'xfe:inlineNote']" mode="normalizeConf.step1"> <xsl:copy> <xsl:apply-templates select="@*" mode="#current"/> <!--on force certains attributs--> <!--cf. schematron conf--> <xsl:attribute name="html-name" select="'a'"/> <xsl:attribute name="html-attribute-href"> <xsl:text>''</xsl:text> <!--valeur sera générée dans XML2HTML (pour avoir des generate-id() homogènes), mais le modèle a besoin qu'on définisse la surcharge ici--> </xsl:attribute> <xsl:attribute name="html-addClass" select="normalize-space(concat('xfe_noteRef', ' ', @html-addClass))"/> <!--<xsl:attribute name="html-xmlNameAsClass" select="'false'"/> non car on pourrait mélanger les note inline et les autres à la reconstruction du XML--> </xsl:copy> </xsl:template> <!--FIXME ! ATTENTION le fait de remplacer les attribut id et idRef par des nouveaux attributs change leur type (et donc ceux des autres éléments html du même nom adjacents) => il faudrait plutôt avoir une instruction pour changer le nom d'un attribut : <attribute xpath="toto/@foo" html-name="bar"/> Sinon c'est surtout @IDNOT sur les note qui doit être transformé en @id, à généraliser (attribut qui sont des id mais n'ont pas le bon nom) hors de notes ? --> <xsl:template match="*:element[starts-with(@type, 'xfe:noteRef(')]" mode="normalizeConf.step1"> <xsl:choose> <xsl:when test="matches(@type, 'xfe:noteRef\(@\w+\)')"> <xsl:variable name="idRefAttributeName" select="replace(@type, '^xfe:noteRef\(@(\w+)\)$', '$1')" as="xs:string"/> <xsl:copy> <xsl:apply-templates select="@*" mode="#current"/> <!--on force certains attributs--> <!--cf. schematron conf--> <xsl:attribute name="html-name" select="'a'"/> <xsl:attribute name="html-attribute-href"> <!--xpath évalué à ne pas mettre en select--> <xsl:text>concat('#', @</xsl:text> <xsl:value-of select="$idRefAttributeName"/> <xsl:text>)</xsl:text> </xsl:attribute> <xsl:attribute name="html-addClass" select="normalize-space(concat('xfe_noteRef', ' ', @html-addClass))"/> <xsl:attribute name="html-ignoreXmlAttributes" select="normalize-space(concat(@html-ignoreXmlAttributes, ' ', $idRefAttributeName))"/> <!--<xsl:attribute name="html-xmlNameAsClass" select="'false'"/> non car on pourrait mélanger les note inline et les autres à la reconstruction du XML--> </xsl:copy> </xsl:when> <xsl:otherwise> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'error'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[ERROR] @type xfe:noteRef must include an attribute name used for idRef. it should look like xfe:noteRef(@idRefAttributeName)</xsl:with-param> </xsl:call-template> <xsl:message terminate="yes"/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="*:element[starts-with(@type, 'xfe:note(')]" mode="normalizeConf.step1"> <xsl:choose> <xsl:when test="matches(@type, 'xfe:note\(@\w+\)')"> <xsl:variable name="idAttributeName" select="replace(@type, '^xfe:note\(@(\w+)\)$', '$1')" as="xs:string"/> <xsl:copy> <xsl:apply-templates select="@*" mode="#current"/> <!--on force certains attributs--> <!--cf. schematron conf--> <xsl:attribute name="html-attribute-id"> <!--xpath évalué à ne pas mettre en select--> <xsl:text>@</xsl:text> <xsl:value-of select="$idAttributeName"/> </xsl:attribute> <xsl:attribute name="html-addClass" select="normalize-space(concat('xfe_note', ' ', @html-addClass))"/> <xsl:attribute name="html-ignoreXmlAttributes" select="normalize-space(concat(@html-ignoreXmlAttributes, ' ', $idAttributeName))"/> <!--<xsl:attribute name="html-xmlNameAsClass" select="'false'"/> non car on pourrait mélanger les note inline et les autres à la reconstruction du XML--> </xsl:copy> </xsl:when> <xsl:otherwise> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'error'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[ERROR] @type xfe:note must include an attribute name used for idRef. it should look like xfe:note(@idRefAttributeName)</xsl:with-param> </xsl:call-template> <xsl:message terminate="yes"/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="*:element[starts-with(@type, 'xfe:multimediaLink(')]" mode="normalizeConf.step1"> <xsl:choose> <xsl:when test="matches(@type, 'xfe:multimediaLink\(@\w+\)')"> <xsl:variable name="idRefAttributeName" select="replace(@type, '^xfe:multimediaLink\(@(\w+)\)$', '$1')" as="xs:string"/> <xsl:copy> <xsl:apply-templates select="@*" mode="#current"/> <!--on force certains attributs--> <!--cf. schematron conf--> <xsl:attribute name="html-name" select="'a'"/> <xsl:attribute name="html-attribute-href"> <!--xpath évalué à ne pas mettre en select--> <xsl:text>concat('</xsl:text> <xsl:value-of select="$xfe:media.url.path"/> <xsl:text>', @</xsl:text> <xsl:value-of select="$idRefAttributeName"/> <xsl:text>)</xsl:text> </xsl:attribute> <xsl:attribute name="html-addClass" select="normalize-space(concat('xfe_multimediaLink', ' ', @html-addClass))"/> <xsl:attribute name="html-ignoreXmlAttributes" select="normalize-space(concat(@html-ignoreXmlAttributes, ' ', $idRefAttributeName))"/> <!--<xsl:attribute name="html-xmlNameAsClass" select="'false'"/> non car on pourrait mélanger les note inline et les autres à la reconstruction du XML--> </xsl:copy> </xsl:when> <xsl:otherwise> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'error'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[ERROR] @type xfe:multimediaLink must include an attribute name used for idRef. it should look like xfe:multimediaLink(@idRefAttributeName)</xsl:with-param> </xsl:call-template> <xsl:message terminate="yes"/> </xsl:otherwise> </xsl:choose> </xsl:template> <!--===== STEP 2 =====--> <!-- - Add @srng-defines attribute (helpfull for the mapping between the conf and the srng schema) - Add automatique @label when none is defined - When $xfe:is-xhtml is true : add some default attributes --> <xsl:template match="*:element" mode="normalizeConf.step2"> <xsl:copy> <!--<xsl:if test="$xfe:srng.is-xhtml"> <xsl:attribute name="html-name" select="xfe:getNameFromXpath(.)"/> <xsl:attribute name="html-xmlNameAsClass" select="'false'"/> <!-\-<xsl:attribute name="html-ignoreXmlAttributes" select="'class'"/> : they all will be ignore in the xsl code-\-> </xsl:if>--> <!--thoses added attributes will be overriden by already setted attributes--> <xsl:apply-templates select="@*" mode="#current"/> <xsl:attribute name="label" select="(@label, tokenize(@xpath, '/')[last()])[1]"/> <xsl:if test="$xfe:conf.hasSchema"> <xsl:attribute name="srng-defines"> <xsl:variable name="xpath.token" select="tokenize(@xpath, '/')" as="xs:string*"/> <xsl:choose> <!--@xpath is absolute--> <xsl:when test="starts-with(@xpath, '/') and not(starts-with(@xpath, '//'))"> <xsl:value-of select="rng:getSRNGdataModelFromXpath(@xpath, $xfe:srng.grammar.normalized, @xpath-filter)/parent::rng:define/@name"/> <!--<xsl:value-of select="rng:getSRNGdataModelFromXpath(@xpath, $xfe:srng.grammar.normalized)/parent::rng:define/@name"/>--> </xsl:when> <xsl:otherwise> <xsl:variable name="xpath.elementName" select="xfe:getNameFromXpath(.)" as="xs:string"/> <xsl:variable name="rngDefinesByName" select="$xfe:srng.grammar.normalized//rng:define[rng:element[1][@name = $xpath.elementName]]" as="element(rng:define)*"/> <xsl:choose> <!--No define with this name in the schema : this is an error in the conf (cf. schematron "no-element-with-this-name-in-the-schema")--> <xsl:when test="count($rngDefinesByName) = 0"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'fatal'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[FATAL] 0 define pour <xsl:copy-of select="$xpath.token"/> (dans conf /element/@xpath='<xsl:value-of select="@xpath"/>')</xsl:with-param> </xsl:call-template> <xsl:message terminate="yes"/> </xsl:when> <!--Only one define with this name in the schema : it *must* be this one--> <xsl:when test="count($rngDefinesByName) = 1"> <xsl:value-of select="$rngDefinesByName/@name"/> </xsl:when> <!--The xpath is a single element name : at least select the defines with the same name --> <xsl:when test="count($xpath.token) = 1"> <!--If the xpath-filter is of kind @foo = 'bar', maybe there is such a static define in the schema (<attribute name="foo"><value>bar</value></attribute>) (and no other same element's name with the same attribute's name which may have the same value)--> <xsl:variable name="xpath-filter" select="normalize-space(@xpath-filter)" as="xs:string"/> <xsl:variable name="xpath.attributeValueTest.reg" as="xs:string"> <xsl:text>^@(.*?)\s*=\s*'(.*?)'</xsl:text> </xsl:variable> <xsl:variable name="rngDefinesByName.xpath-filtered" as="element()*"> <xsl:choose> <xsl:when test="matches($xpath-filter, $xpath.attributeValueTest.reg)"> <xsl:variable name="att.name" select="replace($xpath-filter, $xpath.attributeValueTest.reg, '$1' )" as="xs:string"/> <xsl:variable name="att.value" select="replace($xpath-filter, $xpath.attributeValueTest.reg, '$2' )" as="xs:string"/> <xsl:message use-when="false()">[DEBUG] MATCHES <xsl:value-of select="$xpath-filter"/> [name=<xsl:value-of select="$att.name"/>][value=<xsl:value-of select="$att.value"/>]</xsl:message> <xsl:sequence select="$rngDefinesByName[.//rng:attribute[@name = $att.name][count(*)=1][rng:value = $att.value]]"/> <xsl:message use-when="false()">count $rngDefinesByName = <xsl:value-of select="count($rngDefinesByName)"/></xsl:message> <xsl:message use-when="false()">count $rngDefinesByName filtered = <xsl:value-of select="count($rngDefinesByName[.//rng:attribute[@name = $att.name][count(*)=1][rng:value = $att.value]])"/></xsl:message> </xsl:when> <xsl:otherwise> <xsl:sequence select="$rngDefinesByName"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:choose> <xsl:when test="count($rngDefinesByName.xpath-filtered) = 0"> <xsl:value-of select="$rngDefinesByName/@name" separator=" "/> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'error'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[ERROR] 0 define found for <xsl:copy-of select="$xpath.token"/> (in conf : /element/@xpath='<xsl:value-of select="@xpath"/>')</xsl:with-param> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$rngDefinesByName.xpath-filtered/@name" separator=" "/> </xsl:otherwise> </xsl:choose> </xsl:when> <xsl:otherwise> <!--Solution temporaire sur le parent uniquement :--> <xsl:variable name="xpath.parentName" select="$xpath.token[last() - 1]" as="xs:string"/> <xsl:variable name="rngDefines.parent" select="$xfe:srng.grammar.normalized//rng:define[rng:element[1][@name = $xpath.parentName]]" as="element(rng:define)*"/> <xsl:variable name="rngDefines.filter" as="element(rng:define)*"> <xsl:for-each select="$rngDefinesByName"> <xsl:variable name="rngDefine" select="." as="element(rng:define)"/> <xsl:if test="$rngDefines.parent[rng:defineHasRefName(., $rngDefine/@name)]"> <xsl:sequence select="."/> </xsl:if> </xsl:for-each> </xsl:variable> <xsl:value-of select="$rngDefines.filter/@name" separator=" "/> <!--<xsl:call-template name="filterConfAmbiguousRngDefinesOnRelativeXpath"> <xsl:with-param name="defines" select="$rngDefines"/> <xsl:with-param name="xpath.token" select="$xpath.token"/> <xsl:with-param name="xpath.token.position" select="index-of($xpath.token, last())"/> </xsl:call-template>--> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:attribute> </xsl:if> <xsl:apply-templates mode="#current"/> </xsl:copy> </xsl:template> <!-- FIXME A FINIR ! <xsl:template name="filterConfAmbiguousRngDefinesOnRelativeXpath"> <xsl:param name="defines" required="yes" as="element(rng:define)*"/> <xsl:param name="xpath.tokens" required="yes" as="xs:string*"/> <xsl:param name="xpath.token.position" required="yes" as="xs:integer"/> <xsl:choose> <xsl:when test="count($defines) = 1"> <xsl:sequence select="$defines"/> </xsl:when> <xsl:when test="$xpath.token.position = 0"> <xsl:sequence select="$defines"/> </xsl:when> <xsl:otherwise> <xsl:variable name="current.xpath.name" select="$xpath.tokens[$xpath.token.position]" as="xs:string"/> <xsl:variable name="rngDefines" select="$srng.grammar//rng:define[rng:element[1][@name = $current.xpath.name]]" as="element(rng:define)*"/> <xsl:choose> <!-\-Il n'y a qu'un seul élément avec ce nom définit dans le modèle-\-> <xsl:when test="count($rngDefines) = 1"> </xsl:when> <xsl:otherwise> <xsl:call-template name="filterConfAmbiguousRngDefinesOnRelativeXpath"> <xsl:with-param name="defines" select="$rngDefines"/> <xsl:with-param name="xpath.token" select="remove($xpath.tokens, last())"/> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:template>--> <!--adapte les @match pour le rendre "absolu" (//) => de type "template rule"--> <xsl:template match="@xpath" mode="normalizeConf.step2"> <xsl:attribute name="{name(.)}"> <xsl:choose> <xsl:when test="starts-with(., '/')"> <xsl:value-of select="."/> </xsl:when> <xsl:otherwise> <xsl:value-of select="concat('//', .)"/> </xsl:otherwise> </xsl:choose> </xsl:attribute> </xsl:template> <!--===== STEP 3 =====--> <xsl:template match="/*:conf/*:mapping" mode="normalizeConf.step3"> <xsl:variable name="self" select="self::*" as="element()"/> <xsl:copy> <xsl:apply-templates select="@*" mode="#current"/> <xsl:apply-templates select="node()" mode="#current"/> <xsl:comment>==============================</xsl:comment> <xsl:comment> GENERATED FROM SCHEMA</xsl:comment> <xsl:comment>==============================</xsl:comment> <xsl:apply-templates select="$xfe:srng/rng:grammar/rng:define" mode="normalizeConf.step3.iterate-srng"> <xsl:with-param name="mapping" select="$self" as="element()"/> </xsl:apply-templates> </xsl:copy> </xsl:template> <!--Exclude root define(s)--> <xsl:template match="rng:define[@name = rng:getRootDefines(/rng:grammar)/@name]" mode="normalizeConf.step3.iterate-srng"> <xsl:message use-when="false()"><xsl:value-of select="@name"/> is root define, non need to add it in the conf</xsl:message> </xsl:template> <xsl:template match="rng:define" mode="normalizeConf.step3.iterate-srng"> <xsl:param name="mapping" as="element()"/> <xsl:variable name="rng:element" select="rng:element" as="element(rng:element)"/> <xsl:variable name="rng:element.name" select="rng:element/@name" as="xs:string"/> <!--FIXME : we only check for parents define here, we should actualy look at the full possible context and check against the conf specficied contexts--> <!--FIXME : cals table context is more precise than only parents : we have to exclude them too--> <xsl:variable name="parent.names" select="key('rng:getRefByName', @name)/ancestor::rng:define/rng:element[1]/@name" as="xs:string*"/> <xsl:variable name="unspecified-parent-context-in-conf" as="xs:string*"> <xsl:choose> <xsl:when test="count($mapping/*:element[@xpath = concat('//', $rng:element/@name)]) != 0"> <!--empty sequence--> </xsl:when> <xsl:otherwise> <xsl:variable name="conf.specified.contexts" select="$mapping/*:element[xfe:getNameFromXpath(.) = $rng:element.name]/@xpath" as="xs:string*"/> <xsl:for-each select="$parent.names"> <xsl:variable name="context" select="concat('//', ., '/', $rng:element.name)" as="xs:string"/> <xsl:if test="not($context = $conf.specified.contexts)"> <xsl:value-of select="."/> </xsl:if> </xsl:for-each> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:if test="@name = 'infoCommentaire'"> <xsl:message><xsl:value-of select="@name"/> : <xsl:value-of select="$unspecified-parent-context-in-conf"/></xsl:message> </xsl:if> <xsl:choose> <xsl:when test="count($unspecified-parent-context-in-conf) = 0"/> <xsl:otherwise> <xsl:variable name="html.default.name" as="xs:string"> <xsl:choose> <xsl:when test="rng:isInlineOnly($rng:element, $unspecified-parent-context-in-conf)"> <xsl:text>span</xsl:text> </xsl:when> <xsl:when test="rng:isBlockOnly($rng:element, $unspecified-parent-context-in-conf)"> <xsl:text>div</xsl:text> </xsl:when> <xsl:otherwise> <xsl:text>spanOrdiv</xsl:text> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'fatal'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="xpathContext" select="'_null'"/> <xsl:with-param name="description">[normalizeConf.step3.iterate-srng] Unable to add missing conf element for srng define "<xsl:value-of select="@name"/>". The element might be inline or block depending on the context. Please remove this ambiguity (see the documentation at main/conf/xfe-conf.md)</xsl:with-param> </xsl:call-template> <xsl:message terminate="yes"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <element xpath="{concat('//', $rng:element/@name)}" html-name="{$html.default.name}" srng-defines="{self::rng:define/@name}"/> </xsl:otherwise> </xsl:choose> </xsl:template> <!--===== STEP common =====--> <xsl:template match="node() | @*" mode="normalizeConf.step1 normalizeConf.step2 normalizeConf.step3"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> <!--=========================================--> <!--SRNG Grammar Normalized --> <!--=========================================--> <!--Because tinyMCE interface read the different ref/define to propose adding a node, we duplicate some define for which we want the user don't have to make a choice in attributes values but directly add the good item with a fixed attribute value--> <xsl:template match="rng:define" mode="xfe:srng_duplicateDefineByAttributeValue"> <xsl:variable name="self" select="self::*" as="element()"/> <xsl:variable name="duplicate-define" select="xfe:srng_getConfDuplicatedDefine(.)" as="element()?"/> <!--<xsl:message> rng:define name= <xsl:value-of select="@name"/> - count duplicate-define = <xsl:value-of select="count($duplicate-define)"/> </xsl:message>--> <xsl:choose> <xsl:when test="count($duplicate-define) != 0"> <xsl:variable name="attribute-name" select="$duplicate-define/@attribute-name" as="xs:string"/> <xsl:for-each select=".//rng:attribute[@name = $attribute-name]/rng:choice/rng:value"> <xsl:variable name="value" select="." as="xs:string"/> <xsl:apply-templates select="$self" mode="xfe:srng_duplicateDefineByAttributeValue-copy"> <xsl:with-param name="attribute-name" select="$attribute-name" tunnel="yes"/> <xsl:with-param name="value" select="$value" tunnel="yes"/> </xsl:apply-templates> </xsl:for-each> </xsl:when> <xsl:otherwise> <xsl:next-match/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="rng:define" mode="xfe:srng_duplicateDefineByAttributeValue-copy"> <xsl:param name="value" as="xs:string" tunnel="yes"/> <xsl:copy copy-namespaces="no"> <xsl:apply-templates select="@*" mode="#current"/> <xsl:attribute name="name" select="xfe:srng_duplicatedDefineRenameDef(@name, $value)"/> <xsl:apply-templates select="node()" mode="#current"/> </xsl:copy> </xsl:template> <!--Delete the choice on attribute value, because we will keep only one value--> <xsl:template match="rng:attribute/rng:choice" mode="xfe:srng_duplicateDefineByAttributeValue-copy"> <xsl:param name="attribute-name" as="xs:string" tunnel="yes"/> <xsl:param name="value" as="xs:string" tunnel="yes"/> <xsl:choose> <xsl:when test="ancestor::rng:attribute[1]/@name = $attribute-name"> <!--delete choice--> <xsl:apply-templates mode="#current"/> </xsl:when> <xsl:otherwise> <xsl:next-match/> </xsl:otherwise> </xsl:choose> </xsl:template> <!--Delete other attributes values--> <xsl:template match="rng:attribute/rng:choice/rng:value" mode="xfe:srng_duplicateDefineByAttributeValue-copy"> <xsl:param name="attribute-name" as="xs:string" tunnel="yes"/> <xsl:param name="value" as="xs:string" tunnel="yes"/> <xsl:choose> <xsl:when test="ancestor::rng:attribute[1]/@name = $attribute-name and . != $value"> <!--delete other values--> </xsl:when> <xsl:otherwise> <xsl:next-match/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="rng:ref" mode="xfe:srng_duplicateDefineByAttributeValue xfe:srng_duplicateDefineByAttributeValue-copy"> <xsl:variable name="self" select="self::*" as="element()"/> <xsl:variable name="define" select="rng:getDefine(.)" as="element(rng:define)"/> <xsl:variable name="duplicate-define" select="xfe:srng_getConfDuplicatedDefine($define)" as="element()?"/> <xsl:choose> <xsl:when test="count($duplicate-define) != 0"> <choice xmlns="http://relaxng.org/ns/structure/1.0"> <xsl:for-each select="$define//rng:attribute[@name = $duplicate-define/@attribute-name]/rng:choice/rng:value"> <ref name="{xfe:srng_duplicatedDefineRenameDef($self/@name, .)}"/> </xsl:for-each> </choice> </xsl:when> <xsl:otherwise> <xsl:next-match/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:function name="xfe:srng_duplicatedDefineRenameDef" as="xs:string"> <xsl:param name="define.name" as="xs:string"/> <xsl:param name="attribute.value" as="xs:string"/> <xsl:value-of select="concat($define.name, '_', normalize-space(string-join(tokenize($attribute.value, '\s+'), '_')))"/> </xsl:function> <xsl:function name="xfe:srng_getConfDuplicatedDefine" as="element()?"> <xsl:param name="define" as="element(rng:define)"/> <xsl:sequence select="$xfe:conf.resolved/*:conf/*:srngXmlmodel/*:duplicate-define [@element-name = $define/rng:element/@name] [@attribute-name = $define//rng:attribute[count(*) = 1][rng:choice][count(rng:choice/rng:value) = count(rng:choice/*)]/@name]"/> </xsl:function> <!--default copy--> <xsl:template match="node() | @*" mode="xfe:srng_duplicateDefineByAttributeValue xfe:srng_duplicateDefineByAttributeValue-copy"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> <!--==================================================================--> <!--COMMON FUNCTIONS--> <!--==================================================================--> <!--=================================================--> <!--CONF/RNG functions--> <!--=================================================--> <!--Un template a appeler pour logger la conf normalisée--> <xsl:template name="xfe:log.normalizeConf"> <xsl:if test="$xfe:debug"> <xsl:variable name="step.log.uri" select="resolve-uri('conf.resolved.xml', $log.uri)" as="xs:anyURI"/> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[INFO] writing <xsl:value-of select="$step.log.uri"/></xsl:with-param> </xsl:call-template> <xsl:result-document href="{$step.log.uri}" format="els:xml"> <xsl:sequence select="$xfe:conf.resolved"/> </xsl:result-document> <xsl:variable name="step.log.uri" select="resolve-uri('conf.normalized.xml', $log.uri)" as="xs:anyURI"/> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[INFO] writing <xsl:value-of select="$step.log.uri"/></xsl:with-param> </xsl:call-template> <xsl:result-document href="{$step.log.uri}" format="els:xml"> <xsl:sequence select="$xfe:conf.normalized"/> </xsl:result-document> <xsl:if test="$xfe:conf.hasSchema"> <xsl:variable name="step.log.uri" select="resolve-uri('srng.grammar.normalized.srng', $log.uri)" as="xs:anyURI"/> <xsl:result-document href="{$step.log.uri}" format="els:xml"> <xsl:sequence select="$xfe:srng.grammar.normalized"/> </xsl:result-document> </xsl:if> </xsl:if> </xsl:template> <!--In conf.normalized.xml we added on each element an @srng-define attribute that lists all defines in the schema--> <!--FIXME : préfixe xfe: au lieu de xf:--> <xsl:function name="xf:getConfMappingElementsFromSrng" as="element()*"> <xsl:param name="rngElement" as="element(rng:element)"/> <xsl:variable name="define" select="$rngElement/parent::rng:define" as="element(rng:define)"/> <xsl:sequence select="$xfe:conf.normalized/*:mapping/*:element[xfe:confElementHasRngDefine(., $define/@name)]"/> </xsl:function> <xsl:function name="xfe:getTableCasePattern" as="xs:string"> <xsl:param name="elementName" as="xs:string"/> <xsl:choose> <xsl:when test="upper-case($elementName) = $elementName"> <xsl:value-of select="'uppercase'"/> </xsl:when> <xsl:when test="lower-case($elementName) = $elementName"> <xsl:value-of select="'lowercase'"/> </xsl:when> <xsl:when test="upper-case(substring($elementName, 1, 1)) = substring($elementName, 1, 1) and lower-case(substring($elementName, 2)) = substring($elementName, 2)"> <xsl:value-of select="'titlecase'"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="'error'"/> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'fatal'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="xpathContext" select="'_null'"/> <xsl:with-param name="description">[FATAL][xfe:getTableCasePattern] Impossible de déduire le modèle de nommage des tableaux (uppercase, lowercase ot titlecase)</xsl:with-param> </xsl:call-template> <xsl:message terminate="yes"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xsl:function name="xfe:apply-case" as="xs:string"> <xsl:param name="string" as="xs:string"/> <xsl:param name="nameCase" as="xs:string"/> <xsl:choose> <xsl:when test="$nameCase = 'uppercase'"> <xsl:sequence select="upper-case($string)"/> </xsl:when> <xsl:when test="$nameCase = 'lowercase'"> <xsl:sequence select="lower-case($string)"/> </xsl:when> <xsl:when test="$nameCase = 'titlecase'"> <xsl:sequence select="concat(upper-case(substring($string, 1, 1)), lower-case(substring($string, 2)))"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="$string"/> </xsl:otherwise> </xsl:choose> </xsl:function> <!--=================================================--> <!--XML2HTML functions--> <!--=================================================--> <!--1 arg signature--> <xsl:function name="xfe:getConfMappingElementsFromXML" as="element()*"> <xsl:param name="e" as="element()"/> <xsl:choose> <xsl:when test="$xfe:conf.hasSchema"> <xsl:variable name="e.define.name" as="xs:string"> <xsl:choose> <xsl:when test="$e/@xfe:srng-define != ''"> <xsl:value-of select="$e/@xfe:srng-define"/> </xsl:when> <xsl:otherwise> <xsl:variable name="e.dataModel" select="rng:getSRNGdataModelFromXmlElement($e, $xfe:srng.grammar.normalized)" as="element(rng:element)"/> <xsl:variable name="e.define" select="$e.dataModel/parent::rng:define" as="element(rng:define)"/> <xsl:value-of select="$e.define/@name"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:sequence select="xfe:getConfMappingElementsFromXML($e, $e.define.name)"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="xfe:getConfMappingElementsFromXML($e, ())"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc> <xd:desc> <xd:p>Get all conf elements corresponding to the $e xml element instance : whether xpath based or sharing the same define in the schema</xd:p> <xd:p>Remember we add the schema define name to every conf elements</xd:p> <xd:p>Beware of the plural (elementS) in the name of the function, see the other function "xfe:getConfMappingElementFromXML" (which take the last element) </xd:p> </xd:desc> <xd:param name="e">xml element in xml instance</xd:param> <xd:return>Zero or more conf elements corresponding</xd:return> </xd:doc> <xsl:function name="xfe:getConfMappingElementsFromXML" as="element()*"> <xsl:param name="e" as="element()"/> <xsl:param name="e.define.name" as="xs:string?"/> <!--(so we can call this function for debug with the define's name)--> <!--Ici il faut faire attention car la conf défini du xpath ce qui n'est pas forcément basé sur le srng : ex : si titre prévu en h1 sur infoCommentaire/titre mais que tableau/titre utilise la même définition srng, alors il faut induire qu'un titre de tableau sera forcément un h1 (sauf s'il est lui même redéfini dans la conf plus bas)--> <xsl:variable name="conf.elements" as="element()*"> <xsl:choose> <xsl:when test="$xfe:conf.hasSchema and empty($e.define.name)"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'fatal'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="description">[FATAL] Calling xfe:getConfMappingElementsFromXML with an empty sequence as 2nd agrument "e.define.name" is not allowed when $xfe:conf.hasSchema is true</xsl:with-param> </xsl:call-template> <xsl:message terminate="yes"/> </xsl:when> <xsl:when test="$xfe:conf.hasSchema"> <xsl:sequence select="$xfe:conf.normalized/*:mapping/*:element[xfe:confElementHasRngDefine(., $e.define.name)]"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="$xfe:conf.normalized/*:mapping/*:element"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:choose> <xsl:when test="count($conf.elements) = 1"> <xsl:sequence select="$conf.elements"/> </xsl:when> <xsl:otherwise> <xsl:variable name="conf.matching.elements" as="element()*"> <xsl:for-each select="$conf.elements[tokenize(@xpath, '/')[last()] = local-name($e)]"> <xsl:variable name="conf.element" select="." as="element()"/> <xsl:variable name="xpath-with-filter" select="if(@xpath-filter) then(concat(@xpath, '[', @xpath-filter,']')) else(@xpath)" as="xs:string"/> <xsl:variable name="xml.matching.elements" select="els:evaluate-xpath($xpath-with-filter, $e/root()/*)" as="element()*"/> <xsl:if test="generate-id($e) = $xml.matching.elements/generate-id(.)"> <xsl:sequence select="$conf.element"/> </xsl:if> </xsl:for-each> </xsl:variable> <xsl:variable name="conf.matching.elements.theMorePreciseXpath" as="element()*" select="$conf.matching.elements[ count(tokenize(@xpath, '/')) = max( for $e in $conf.matching.elements return count(tokenize($e/@xpath, '/')) )]"/> <xsl:choose> <!--There is one (or more) more precise xpath corresponding conf element--> <xsl:when test="count($conf.matching.elements.theMorePreciseXpath) != 0"> <xsl:sequence select="$conf.matching.elements.theMorePreciseXpath"/> </xsl:when> <xsl:when test="not($xfe:conf.hasSchema)"> <!--<!-\-Only the the root may not be declared in the conf-\-> <xsl:if test="$e/ancestor::*"> <xsl:message terminate="yes">[FATAL] No element found in the conf for <xsl:value-of select="els:displayNode($e)"/></xsl:message> </xsl:if>--> </xsl:when> <!--Otherwise : look if there is a define corresponding element in the conf--> <xsl:otherwise> <!-- on vérifie qu'il n'y a pas de règles dans la conf qui s'applique au même élément par sa définition (mais pas par son xpath)--> <xsl:variable name="e.srng-define" select="$e.define.name" as="xs:string"/> <xsl:variable name="e.define" select="$xfe:srng.grammar.normalized//rng:define[@name = $e.srng-define]" as="element(rng:define)?"/> <xsl:variable name="conf.matchingDefine.elements" as="element()*"> <!--If the xml File contains an unvalid element we must not through an error--> <xsl:if test="count($e.define) != 0"> <xsl:sequence select="$conf.elements[xfe:confElementHasRngDefine(., $e.define.name)]"/> </xsl:if> </xsl:variable> <xsl:if test="count($conf.matchingDefine.elements) != 0"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="xpathContext" select="$e"/> <xsl:with-param name="description">[INFO] surcharge de conf induite sur <xsl:value-of select="els:displayNode($e)"/></xsl:with-param> </xsl:call-template> <!--<xsl:message use-when="true()">e.srng-define= <xsl:value-of select="$e.srng-define"/></xsl:message> <xsl:message use-when="true()">e.define =<xsl:value-of select="$e.define/@name"/></xsl:message> <xsl:message use-when="true()">count $conf.matchingDefine.elements = <xsl:value-of select="count($conf.matchingDefine.elements)"/></xsl:message>--> <xsl:if test="count($conf.matchingDefine.elements) gt 1"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="level" select="'warning'"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="xpathContext" select="$e"/> <xsl:with-param name="description"> <xsl:value-of select="concat('[WARNING] ', count($conf.matchingDefine.elements), ' elements de surcharge induite sur ', els:displayNode($e), ', on a pris le dernier ?')"/> <xsl:value-of select="concat('
 xpath : ', els:get-xpath($e))"/> <xsl:for-each select="$conf.matchingDefine.elements"> <xsl:value-of select="concat('
 ', els:displayNode($e))"/> </xsl:for-each> </xsl:with-param> </xsl:call-template> </xsl:if> <xsl:sequence select="$conf.matchingDefine.elements[last()]"/> </xsl:if> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:function> <xsl:function name="xfe:confElementHasRngDefine" as="xs:boolean"> <xsl:param name="e" as="element()"/> <!--element dans la conf (sans namespace)--> <xsl:param name="defineName" as="xs:string"/> <xsl:sequence select="tokenize($e/@srng-defines, ' ') = $defineName"/> </xsl:function> <xsl:function name="xfe:getConfMappingElementFromXML" as="element()*"> <xsl:param name="e" as="element()"/> <!--comme en css, on prend la dernière règle qui matche--> <xsl:sequence select="xfe:getConfMappingElementsFromXML($e)[last()]"/> </xsl:function> <!--=================================================--> <!--HTML2XML functions--> <!--=================================================--> <!--Get conf definition element from any html element : - result can be empty if the element is not defined in the conf. - if multiple definition found, falling back to the first occurence + xsl:message --> <!--FIXME : another method could be to get the define in the html.rng with a validator (msv.jar) and then just read the PI we have inserted--> <xsl:function name="xfe:getConfMappingFromHTML" as="element()?"> <!--Assume Schematron conf : - pattern-every-xfe-type-that-infer-a-link-has-a-class-and-href-attributes-and-is-unique-for-same-xml-name - no-added-class-equal-xml-element-name - unique-html-name-when-no-class html.rng schema : - class attribute are strict values (order specified)--> <xsl:param name="e" as="element()"/><!--html:*--> <!--xfe-XML2HTML always add the xml element's name at first position into @class (when it add it)--> <xsl:variable name="class1" select="tokenize($e/@class, '\s+')[1]" as="xs:string?"/> <xsl:variable name="name" select="local-name($e)" as="xs:string?"/> <xsl:choose> <!--============================--> <!--SPECIFIC--> <!--============================--> <!--=== TABLES ===--> <!--type="cals:table/html:table"--> <xsl:when test="$e/self::div/table"> <!--TODO : get the conf <element type="cals:table or html:table"/> using the div class--> </xsl:when> <xsl:when test="local-name($e) = ('table' , 'colgroup' , 'col' , 'thead' , 'tbody' , 'tfoot' , 'tr' , 'td' , 'th') or local-name($e) = ('tgroup', 'colspec', 'thead', 'tbody', 'tfoot', 'row', 'entry')"> <!--schematron : no-mapping-for-table-elements-use-type-instead => nothing--> </xsl:when> <!--=== TITLE ===--> <!--type="xfe:title-xx" => <xx class="xfe_title-yy">--> <xsl:when test="some $class in tokenize($e/@class, $els:regAnySpace) satisfies (starts-with($class, 'xfe_title-'))"> <xsl:variable name="xfe_title.class" select="(tokenize($e/@class, $els:regAnySpace)[starts-with(., 'xfe_title-')])[1]" as="xs:string"/> <xsl:variable name="conf.mappingElements" select="$xfe:conf.normalized/*:mapping/*:element[@html-addClass = $xfe_title.class]" as="element()*"/> <xsl:sequence select="xfe:applyCommonfiltersOnConfMappingElements($e, $conf.mappingElements)"/> </xsl:when> <!--=== LIST ===--> <!--type="xfe:list(xx)" => <ul/ol data-xfe-listType="...">--> <xsl:when test="$e/@*[local-name(.) = concat($xfe:dataXfeAttribute.prefix, 'listType')]"> <!--schematron : - mapping-for-list-elements-use-type-instead - mapping-for-li-elements-but-no-xfe-list-type-defined - xfe-list-must-have-html-name-ul-or-ol - when-xfe-list-defined-li-mapping-must-be-defined --> <xsl:variable name="conf.mappingElements" select="$xfe:conf.normalized/*:mapping/*:element[starts-with(@type, 'xfe:list(')][@html-name = $name]" as="element()*"/> <xsl:sequence select="xfe:applyCommonfiltersOnConfMappingElements($e, $conf.mappingElements)"/> </xsl:when> <!--should be ok with the default behaviour--> <!--<xsl:when test="$name = 'li'"/>--> <!--=== FOOTNOTES ===--> <!-- type="xfe:noteRef(xx)" => <a class="[xmlName] xfe_noteRef [addClass]"> type="xfe:inlineNote" => <a class="[xmlName] xfe_noteRef [addClass]"> type="xfe:note(xx)" => <xx class="[xmlName] xfe_note [addClass]"> --> <xsl:when test="els:hasClass($e, 'xfe_noteRef')"> <xsl:variable name="conf.mappingElements" as="element()*" select="$xfe:conf.normalized/*:mapping/*:element[starts-with(@type, 'xfe:noteRef') or @type = 'xfe:inlineNote']"/> <xsl:sequence select="xfe:applyCommonfiltersOnConfMappingElements($e, $conf.mappingElements)"/> </xsl:when> <xsl:when test="els:hasClass($e, 'xfe_note')"> <xsl:variable name="conf.mappingElements" as="element()*" select="$xfe:conf.normalized/*:mapping/*:element[starts-with(@type, 'xfe:note(')]"/> <xsl:sequence select="xfe:applyCommonfiltersOnConfMappingElements($e, $conf.mappingElements)"/> </xsl:when> <!--=== LINKS ===--> <!--type="xfe:externalLinkType" => <a class="[xmlName] [addClass]">--> <!--No way to discern those external link we have to deal with every links, so fallback to default behaviour (otherwise)--> <!--We sould alway get a confElement for links because of schematron rules : - every-xfe-type-that-infer-a-link-has-a-class-and-href-attributes-and-is-unique-for-same-xml-name - no-added-class-equal-xml-element-name - unique-html-name-when-no-class --> <!--============================--> <!--COMMON--> <!--============================--> <xsl:otherwise> <!--There is a class1 which should be the xml element's name--> <!--exclude any conf definitions that has already been treated--> <xsl:variable name="conf.mappingElements" select="$xfe:conf.normalized/*:mapping/*:element [not(@type = 'cals:table')] [not(@type = 'html:table')] [not(starts-with(@type, 'xfe:title-'))] [not(starts-with(@type, 'xfe:list('))] [not(starts-with(@type, 'xfe:noteRef('))] [not(starts-with(@type, 'xfe:note('))] [not(@type = 'inlineNote')] " as="element()*"/> <xsl:sequence select="xfe:applyCommonfiltersOnConfMappingElements($e, $conf.mappingElements)"/> </xsl:otherwise> </xsl:choose> </xsl:function> <!--When multiple definition has been found in xfe:getConfMappingFromHTML(), this function filters them with common rules based on conf attributes : - @html-name - @html-xmlClassAsName - @html-addClass --> <xsl:function name="xfe:applyCommonfiltersOnConfMappingElements" as="element()?"> <xsl:param name="e" as="element()"/><!--html element--> <xsl:param name="conf.mappingElements" as="element()*"/> <!--xfe-XML2HTML always add the xml element's name at first position into @class (when it add it) html.rng schema : - class attribute are strict values (order specified)--> <xsl:variable name="class1" select="normalize-space(tokenize($e/@class, '\s+')[1][not(starts-with(., 'xfe_'))])" as="xs:string?"/> <xsl:variable name="name" select="local-name($e)" as="xs:string?"/> <xsl:message use-when="false()">[DEBUG][xfe:applyCommonfiltersOnConfMappingElements] e=<xsl:value-of select="els:displayNode($e)"/></xsl:message> <xsl:message use-when="false()">[DEBUG][xfe:applyCommonfiltersOnConfMappingElements] name=<xsl:value-of select="$name"/> class1=<xsl:value-of select="$class1"/></xsl:message> <xsl:message use-when="false()">[DEBUG][xfe:applyCommonfiltersOnConfMappingElements] count($conf.mappingElements) = <xsl:value-of select="count($conf.mappingElements)"/></xsl:message> <xsl:variable name="conf.mappingElements.filtered" as="element()*"> <xsl:choose> <xsl:when test="count($conf.mappingElements) = 0"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="xpathContext" select="$e"/> <xsl:with-param name="description">[INFO][xfe:applyCommonfiltersOnConfMappingElements] No elements found in conf for html <xsl:value-of select="els:displayNode($e)"/>. </xsl:with-param> </xsl:call-template> </xsl:when> <xsl:when test="count($conf.mappingElements) = 1"> <xsl:sequence select="$conf.mappingElements"/> </xsl:when> <xsl:otherwise> <xsl:variable name="conf.mappingElements.filteredByHtmlName" as="element()*"> <xsl:choose> <!--default html-element name is calculated with the schema (inline or block)--> <xsl:when test="$name = ('span', 'div')"> <!--FIXME : if a simple element declaration without html-name exists in the conf, then it would not always be the good one cf. conf/_test/xfe-conf.xml <element xpath="notes" label="footnotes"/> => we can actually not know --> <!--<xsl:sequence select="$conf.mappingElements[not(@html-name) or @html-name = $name]"/>--> <xsl:sequence select="$conf.mappingElements"/> </xsl:when> <!--if the name is not span or div, then it has been necessarily specified in the conf--> <xsl:otherwise> <xsl:sequence select="$conf.mappingElements[@html-name = $name]"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:message use-when="false()">[DEBUG][xfe:applyCommonfiltersOnConfMappingElements] count($conf.mappingElements.filteredByHtmlName) = <xsl:value-of select="count($conf.mappingElements.filteredByHtmlName)"/></xsl:message> <xsl:choose> <xsl:when test="count($conf.mappingElements.filteredByHtmlName) = 1"> <xsl:sequence select="$conf.mappingElements.filteredByHtmlName"/> </xsl:when> <xsl:otherwise> <xsl:variable name="conf.mappingElements.filteredByClass" as="element()*"> <xsl:choose> <!--when $class1 is empty, then it has been necessarily specified in the conf with @html-xmlNameAsClass="false"--> <xsl:when test="$class1 = ''"> <xsl:sequence select="$conf.mappingElements.filteredByHtmlName[@html-xmlNameAsClass = 'false']"/> </xsl:when> <!--when @class is not empty, it could be : - wether the @html-xmlNameAsClass - or any @html-addClass--> <xsl:otherwise> <xsl:variable name="conf.mappingElements.filteredByXmlNameAsClass" as="element()*" select="$conf.mappingElements.filteredByHtmlName[xfe:getNameFromXpath(.) = $class1]"/> <!-- It could be an empty sequence : that means the element is not defined in the conf--> <xsl:choose> <xsl:when test="count($conf.mappingElements.filteredByXmlNameAsClass) = (0, 1)"> <xsl:sequence select="$conf.mappingElements.filteredByXmlNameAsClass"/> </xsl:when> <xsl:otherwise> <!-- filtering on @html-addClass--> <xsl:variable name="conf.mappingElements.filteredByHtmlAddClass" as="element()*"> <xsl:choose> <!--there is no @html-addClass left in the conf --> <xsl:when test="count($conf.mappingElements.filteredByXmlNameAsClass[@html-addClass]) = 0"> <!--do not filter on it--> <xsl:sequence select="$conf.mappingElements.filteredByXmlNameAsClass"/> </xsl:when> <!--there are added class that matches the current class--> <xsl:when test="count($conf.mappingElements.filteredByXmlNameAsClass[tokenize(@html-addClass, '\s+') = tokenize($e/@class, '\s+')]) != 0"> <!--filter on it--> <xsl:sequence select="$conf.mappingElements.filteredByXmlNameAsClass[tokenize(@html-addClass, '\s+') = tokenize($e/@class, '\s+')]"/> </xsl:when> <xsl:otherwise> <!--keep the last filter active--> <!--FIXME : we could exclude all @html-addClass that doesn't match--> <xsl:sequence select="$conf.mappingElements.filteredByXmlNameAsClass"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:sequence select="$conf.mappingElements.filteredByHtmlAddClass"/> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:sequence select="$conf.mappingElements.filteredByClass"/> <xsl:message use-when="false()">[DEBUG][xfe:applyCommonfiltersOnConfMappingElements] count($conf.mappingElements.filteredByClass) = <xsl:value-of select="count($conf.mappingElements.filteredByClass)"/></xsl:message> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:choose> <xsl:when test="count($conf.mappingElements.filtered) = 0"> <!--<xsl:message>[INFO][xfe:applyCommonfiltersOnConfMappingElements] <xsl:value-of select="count($conf.mappingElements.filtered)"/> elements found in conf for html <xsl:value-of select="els:displayNode($e)"/>.</xsl:message>--> </xsl:when> <xsl:when test="count($conf.mappingElements.filtered) = 1"> <xsl:sequence select="$conf.mappingElements.filtered"/> </xsl:when> <xsl:otherwise> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'warning'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="xpathContext" select="$e"/> <xsl:with-param name="description">[WARNING][xfe:applyCommonfiltersOnConfMappingElements] <xsl:value-of select="count($conf.mappingElements.filtered)"/> elements found in conf for html <xsl:value-of select="els:displayNode($e)"/>. Falling back to first occurence</xsl:with-param> </xsl:call-template> <xsl:if test="count($conf.mappingElements.filtered) != 0"> <xsl:call-template name="els:log"> <xsl:with-param name="xsltName" select="els:getFileName(static-base-uri())"/> <xsl:with-param name="code" select="$els:log.level.code"/> <xsl:with-param name="alert" select="true()"/> <xsl:with-param name="level" select="'warning'"/> <xsl:with-param name="markup" select="false()"/> <xsl:with-param name="xpathContext" select="$e"/> <xsl:with-param name="description"><xsl:text>conf elements found : </xsl:text> <xsl:for-each select="$conf.mappingElements.filtered"> <xsl:text> </xsl:text> <xsl:value-of select="els:displayNode(.)"/> <xsl:text> </xsl:text> </xsl:for-each> </xsl:with-param> </xsl:call-template> </xsl:if> <xsl:sequence select="$conf.mappingElements.filtered[1]"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xsl:function name="xfe:getXmlELementName" as="xs:string"> <xsl:param name="e" as="element()"/> <!--élement html--> <xsl:variable name="result" as="xs:string"> <xsl:choose> <!--This could be avoid because but we will add the good class while "specific-cleaning" so the html is always valid From the good class, the element name should be retrieve. => But actually there are case where the good class doesn't allow to retrieve the good name (ex : when xml <article> becomes <body>, we should be able to do the reverse <body> => <article>) => So keep this xsl:when here--> <xsl:when test="$xfe:srng.grammar.rootIsSingle and $e/self::html:body"> <xsl:value-of select="rng:getRootElementsName($xfe:srng.grammar.normalized)[1]"/> </xsl:when> <xsl:when test="$xfe:srng.is-xhtml"> <xsl:value-of select="local-name($e)"/> </xsl:when> <xsl:otherwise> <xsl:variable name="conf.mappingElement" select="xfe:getConfMappingFromHTML($e)" as="element()*"/> <xsl:choose> <xsl:when test="count($conf.mappingElement) = 1"> <xsl:value-of select="xfe:getNameFromXpath($conf.mappingElement)"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="tokenize($e/@class, $els:regAnySpace)[1]"/> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:choose> <xsl:when test="normalize-space($result) != ''"> <xsl:value-of select="$result"/> </xsl:when> <xsl:otherwise> <xsl:message terminate="yes">[FATAL][xfe:getXmlELementName] Unable to get the xml element's name for <xsl:value-of select="els:displayNode($e)"/> at <xsl:value-of select="els:get-xpath($e)"/></xsl:message> </xsl:otherwise> </xsl:choose> </xsl:function> <!--FIXME xslLib ? : but xpath must be a path type a/b/c (nothing else, no *, no predicates)--> <xsl:function name="xfe:getNameFromXpath" as="xs:string"> <xsl:param name="e" as="element()"/> <xsl:value-of select="tokenize($e/@xpath, '/')[last()]"/> </xsl:function> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" xmlns="http://relaxng.org/ns/structure/1.0" xpath-default-namespace="http://relaxng.org/ns/structure/1.0" exclude-result-prefixes="#all" version="3.0"> <xsl:import href="els-common.xsl"/> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>XSLT functions/templates library to extract information or transform Relax NG schema</xd:p> <xd:p>The RNG schema provided should be simplified (cf. http://www.relaxng.org/spec-20011203.html), there should be at least one element by define and one define by element.</xd:p> </xd:desc> </xd:doc> <!--FIXME : adding a check on (s)rng format before proceding each step/function ?--> <xsl:key name="rng:getDefineByName" match="define" use="@name"/> <xsl:key name="rng:getRefByName" match="ref" use="@name"/> <!-- NEED context item here ! <xsl:function name="rng:getDefineByName" as="element(define)*"> <xsl:param name="name" as="xs:string"/> <xsl:sequence select="key('rng:getDefineByName', $name)"/> </xsl:function> <xsl:function name="rng:getRefByName" as="element(define)*"> <xsl:param name="name" as="xs:string"/> <xsl:sequence select="key('rng:getRefByName', $name)"/> </xsl:function>--> <xsl:function name="rng:getRootNamespaceUri" as="xs:string"> <xsl:param name="grammar" as="element(rng:grammar)"/> <xsl:choose> <xsl:when test="$grammar/start/choice/ref"> <xsl:value-of select="(rng:getDefine($grammar/start/choice/ref[1])/element/ancestor-or-self::*[@ns][1]/@ns, $grammar/descendant-or-self::*[@ns][last()])[1]"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="(rng:getDefine($grammar/start/ref[1])/element/ancestor-or-self::*[@ns][1]/@ns, $grammar/descendant-or-self::*[@ns][last()])[1]"/> </xsl:otherwise> </xsl:choose> </xsl:function> <xd:doc xml:lang="en"> <xd:desc> <xd:p>Indicates if there is only one possible root element for a given grammar</xd:p> </xd:desc> <xd:param name="grammar">SRNG grammar element</xd:param> <xd:return>true/false</xd:return> </xd:doc> <xsl:function name="rng:rootIsSingle" as="xs:boolean"> <xsl:param name="grammar" as="element(rng:grammar)"/> <!-- in SRNG, each element is in a new define, attributes are expanded, so the start has only ref to elements--> <xsl:value-of select="count($grammar/start//ref) = 1"/> </xsl:function> <xsl:function name="rng:getRootDefines" as="element(define)*"> <xsl:param name="grammar" as="element(rng:grammar)"/> <xsl:sequence select="$grammar/start//ref/rng:getDefine(.)"/> </xsl:function> <xsl:function name="rng:getRootElementsName" as="xs:string*"> <xsl:param name="grammar" as="element(rng:grammar)"/> <xsl:sequence select="rng:getRootDefines($grammar)[1]/rng:element/@name"/> </xsl:function> <xsl:function name="rng:getDefine" as="element(define)*"> <xsl:param name="ref" as="element(ref)"/> <xsl:sequence select="key('rng:getDefineByName', $ref/@name, $ref/root())"/> </xsl:function> <xsl:function name="rng:defineHasRefName" as="xs:boolean"> <xsl:param name="define" as="element(define)"/> <xsl:param name="refName" as="xs:string"/> <xsl:sequence select="count($define//ref[@name = $refName]) != 0"/> </xsl:function> <xsl:function name="rng:isInline" as="xs:boolean"> <xsl:param name="rngElement" as="element(rng:element)"/> <!--no parent (no ref) for root element--> <xsl:param name="rngParent" as="element(element)?"/> <xsl:variable name="rngRefs" select="$rngParent//ref[rng:getDefine(.)/element is $rngElement]" as="element(ref)+"/> <xsl:choose> <xsl:when test="count($rngRefs) = 0"> <xsl:message terminate="yes">[ERROR][rng:isInline] No rng:ref found for rngElement "<xsl:value-of select="$rngElement/@name"/>" and $rngParent "<xsl:value-of select="$rngParent/@name"/>"</xsl:message> </xsl:when> <xsl:when test="count($rngRefs) = 1"> <xsl:sequence select="rng:refIsInline($rngRefs)"/> </xsl:when> <xsl:otherwise> <xsl:variable name="rngRef.1.isInline" select="rng:refIsInline($rngRefs[1])" as="xs:boolean"/> <xsl:choose> <!--Every ref has the same type (inline or not inline) so we just return the first one--> <xsl:when test="every $rngRef in $rngRefs satisfies rng:refIsInline($rngRef) = $rngRef.1.isInline"> <xsl:sequence select="$rngRef.1.isInline"/> </xsl:when> <xsl:otherwise> <xsl:message terminate="yes">[ERROR][rng:isInline] <xsl:value-of select="count($rngRefs)"/> rng:ref found, some are inline and some are not ! rngElement "<xsl:value-of select="$rngElement/@name"/>" and $rngParent "<xsl:value-of select="$rngParent/@name"/>"</xsl:message> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:function> <xsl:function name="rng:refIsInline" as="xs:boolean"> <xsl:param name="ref" as="element(rng:ref)"/> <!--see http://relaxng.org/spec-20011203.html#IDA0FZR--> <!-- 2 possibilités : - mixed qui est converti (srng) en interleave {pattern} text ex : <interleave> <text/> <zeroOrMore> <choice> <ref name="e"/> <ref name="ind"/> - une autre structure de type ex : <oneOrMore> <choice> <text/> <ref name="ITAL"/> --> <xsl:sequence select="exists($ref/ancestor::interleave/text) or exists($ref/parent::*/text)"/> </xsl:function> <xsl:function name="rng:isInlineOnly" as="xs:boolean"> <xsl:param name="rngElement" as="element(rng:element)"/> <xsl:variable name="rngDefine" select="$rngElement/parent::define" as="element(define)"/> <xsl:sequence select="every $rngParent in $rngElement/root()//define//ref[@name = $rngDefine/@name]/ancestor::define/rng:element[1] satisfies rng:isInline($rngElement, $rngParent)"/> </xsl:function> <xsl:function name="rng:isInlineOnly" as="xs:boolean"> <xsl:param name="rngElement" as="element(rng:element)"/> <xsl:param name="parents.name.scope" as="xs:string*"/> <xsl:variable name="rngDefine" select="$rngElement/parent::define" as="element(define)"/> <xsl:sequence select="every $rngParent in $rngElement/root()//define//ref[@name = $rngDefine/@name]/ancestor::define/rng:element[1][@name = $parents.name.scope] satisfies rng:isInline($rngElement, $rngParent)"/> </xsl:function> <xsl:function name="rng:isBlockOnly" as="xs:boolean"> <xsl:param name="rngElement" as="element(rng:element)"/> <xsl:variable name="rngDefine" select="$rngElement/parent::define" as="element(define)"/> <xsl:sequence select="every $rngParent in $rngElement/root()//define//ref[@name = $rngDefine/@name]/ancestor::define/rng:element[1] satisfies not(rng:isInline($rngElement, $rngParent))"/> </xsl:function> <xsl:function name="rng:isBlockOnly" as="xs:boolean"> <xsl:param name="rngElement" as="element(rng:element)"/> <xsl:param name="parents.name.scope" as="xs:string*"/> <xsl:variable name="rngDefine" select="$rngElement/parent::define" as="element(define)"/> <xsl:sequence select="every $rngParent in $rngElement/root()//define//ref[@name = $rngDefine/@name]/ancestor::define/rng:element[1][@name = $parents.name.scope] satisfies not(rng:isInline($rngElement, $rngParent))"/> </xsl:function> <xsl:function name="rng:defineHasCircularRef" as="xs:boolean"> <xsl:param name="define" as="element(define)"/> <xsl:variable name="define.name" select="$define/@name" as="xs:string"/> <xsl:sequence select="exists($define//ref[@name = $define.name])"/> </xsl:function> <xsl:function name="rng:getSRNGdataModelFromXmlElement" as="element(rng:element)?"> <xsl:param name="e" as="element()"/> <xsl:param name="grammar" as="element(rng:grammar)"/> <xsl:sequence select="rng:getSRNGdataModelFromXpath(els:get-xpath($e, '', false()), $grammar, ())"/> </xsl:function> <!--2 args signature--> <xsl:function name="rng:getSRNGdataModelFromXpath" as="element(rng:element)?"> <xsl:param name="xpath" as="xs:string"/> <xsl:param name="grammar" as="element(rng:grammar)"/> <xsl:sequence select="rng:getSRNGdataModelFromXpath($xpath, $grammar, ())"/> </xsl:function> <xd:doc> <xd:desc> <xd:p>Given an xpath and a (simplified) rng:grammar, this function tries to get the associated "rng:define/rng:element"</xd:p> <xd:p>CAUTION ! This function may take a long time, because it needs to process the whole schema for each part of the xpath</xd:p> </xd:desc> <xd:param name="xpath">Absolute xpath of form "/a/b/c" (not "//a" neither "b/c")</xd:param> <xd:param name="grammar">the (simplified) RNG root element</xd:param> <xd:param name="predicate">[OPTIONAL] Specific predicate on the tested element (i.e. "c" if a/b/c) like @foo='bar' (it may helps finding the last ref)</xd:param> <xd:return>Should return the rng:element (within the rng:grammar) corresponding to the xpath</xd:return> </xd:doc> <xsl:function name="rng:getSRNGdataModelFromXpath" as="element(rng:element)?"> <xsl:param name="xpath" as="xs:string"/> <xsl:param name="grammar" as="element(rng:grammar)"/> <xsl:param name="predicate" as="xs:string?"/> <xsl:variable name="xpath.tokenized" select="tokenize($xpath, '/')" as="xs:string*"/> <xsl:variable name="xpath.rootName" select="$xpath.tokenized[2]" as="xs:string"/> <!--dans start on cherche la référence à xpath.rootName--> <xsl:variable name="rngRootRef" select="$grammar/start//ref[rng:getDefine(.)/element[1]/@name = $xpath.rootName]" as="element(rng:ref)?"/> <xsl:choose> <!--Il y en a une ref dans le start, tout va bien : on peut initialiser rng:getSRNGdataModelReccurse()--> <xsl:when test="count($rngRootRef) = 1"> <xsl:variable name="getSRNGdataModelReccurse" select="rng:getSRNGdataModelReccurse(rng:getDefine($rngRootRef)/element[1], string-join($xpath.tokenized[position() gt 2], '/'), $predicate)" as="element(rng:element)?"/> <xsl:sequence select="$getSRNGdataModelReccurse"/> <!--<xsl:choose> <xsl:when test="count($getSRNGdataModelReccurse) = 0"> <xsl:sequence select="$getSRNGdataModelReccurse"/> </xsl:when> <xsl:otherwise> <xsl:message> <xsl:message terminate="yes"> <xsl:text>[ERROR] No rng:ref found in rng:start element for </xsl:text><xsl:value-of select="$xpath.rootName"/> <xsl:text> xpath=</xsl:text><xsl:value-of select="$xpath"/> <xsl:text> srng uri :</xsl:text><xsl:value-of select="base-uri($grammar)"/> </xsl:message> </xsl:message> </xsl:otherwise> </xsl:choose>--> </xsl:when> <xsl:when test="count($rngRootRef) = 0"> <xsl:message terminate="no"> <xsl:text>[ERROR] No rng:ref found in rng:start element for </xsl:text><xsl:value-of select="$xpath.rootName"/> <xsl:text> xpath=</xsl:text><xsl:value-of select="$xpath"/> <xsl:text> srng uri :</xsl:text><xsl:value-of select="base-uri($grammar)"/> </xsl:message> </xsl:when> </xsl:choose> <!--<xsl:sequence select="rng:getSRNGdataModelReccurse(rng:getDefine($grammar/start/ref[1])/element[1], string-join($xpath.tokenized[position() gt 2], '/'))"/>--> </xsl:function> <!--Fonction "PRIVATE" utilisée uniquement pour résoudre rng:getSRNGdataModel()--> <xsl:function name="rng:getSRNGdataModelReccurse" as="element(rng:element)?"> <xsl:param name="rngParentElement" as="element(rng:element)"/> <!--<element name="a"/>--> <xsl:param name="xpathFromDataModel" as="xs:string"/> <!--(a)/b/c/d--> <xsl:param name="predicate" as="xs:string?"/> <xsl:message use-when="false()">rng:getSRNGdataModelReccurse(<xsl:value-of select="els:displayNode($rngParentElement)"/>, '<xsl:value-of select="$xpathFromDataModel"/>')</xsl:message> <xsl:variable name="xpathFromDataModel.tokenized" select="tokenize($xpathFromDataModel, '/')" as="xs:string*"/> <xsl:choose> <!--on a résolu le xpath, donc à l'étape précédente on était bon => rngParentElement--> <xsl:when test="count($xpathFromDataModel.tokenized) = 0"> <xsl:sequence select="$rngParentElement"/> </xsl:when> <!--Sinon on appele la même fonction réccursivement--> <xsl:otherwise> <xsl:variable name="currentName" select="$xpathFromDataModel.tokenized[1]" as="xs:string"/> <!--Dans a je cherche la référence à b--> <xsl:variable name="rngRef" as="element(rng:ref)?"> <xsl:choose> <!--Last step = end of the xpath = tested element : one may add the predicate--> <xsl:when test="count($xpathFromDataModel.tokenized) = 1"> <xsl:sequence select="rng:getRefByElementName($rngParentElement, $currentName, $predicate)"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="rng:getRefByElementName($rngParentElement, $currentName)"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:choose> <!--Il y en a une ref, tout va bien : on continue avec <element name="b"> et xpath = c/d --> <xsl:when test="count($rngRef) = 1"> <xsl:sequence select="rng:getSRNGdataModelReccurse(rng:getDefine($rngRef[1])/element[1], string-join($xpathFromDataModel.tokenized[not(position() = 1)], '/'), $predicate)"/> </xsl:when> <xsl:when test="count($rngRef) = 0"> <xsl:message terminate="no"> <xsl:text>[ERROR] No rng:ref found for </xsl:text><xsl:value-of select="els:get-xpath($rngParentElement)"/> <xsl:text> xpath : </xsl:text><xsl:value-of select="$xpathFromDataModel"/> <xsl:text> predicate : </xsl:text><xsl:value-of select="$predicate"/> <xsl:text> currentName : </xsl:text><xsl:value-of select="$currentName"/> <xsl:text> srng uri :</xsl:text><xsl:value-of select="base-uri($rngParentElement)"/> </xsl:message> </xsl:when> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:function> <xsl:function name="rng:getRefByElementName" as="element(rng:ref)?"> <xsl:param name="rngElement" as="element(rng:element)"/> <xsl:param name="refName" as="xs:string"/> <xsl:param name="predicate" as="xs:string?"/> <xsl:variable name="rngRef.tmp1" select="$rngElement//ref[rng:getDefine(.)[element[1]/@name = $refName]]" as="element(rng:ref)*"/> <xsl:variable name="rngRef.tmp2" as="element(rng:ref)*"> <xsl:choose> <xsl:when test="count($rngRef.tmp1) = 1 "> <xsl:sequence select="$rngRef.tmp1"/> </xsl:when> <xsl:when test="count($predicate[normalize-space(.)]) != 0"> <!--If the predicates is of kind @foo = 'bar', maybe there is such a static define in the schema (<attribute name="foo"><value>bar</value></attribute>) (and no other same element's name with the same attribute's name which may have the same value)--> <xsl:variable name="predicate" select="normalize-space($predicate)" as="xs:string"/> <xsl:variable name="xpath.attributeValueTest.reg" as="xs:string"> <xsl:text>^@(.*?)\s*=\s*'(.*?)'</xsl:text> </xsl:variable> <xsl:choose> <!--<!-\-DEBUG-\-><xsl:when test="true()"><xsl:sequence select="$rngRef.tmp"/></xsl:when>--> <xsl:when test="matches($predicate, $xpath.attributeValueTest.reg)"> <xsl:variable name="att.name" select="replace($predicate, $xpath.attributeValueTest.reg, '$1' )" as="xs:string"/> <xsl:variable name="att.value" select="replace($predicate, $xpath.attributeValueTest.reg, '$2' )" as="xs:string"/> <xsl:message use-when="false()">[DEBUG] MATCHES <xsl:value-of select="$predicate"/> [name=<xsl:value-of select="$att.name"/>][value=<xsl:value-of select="$att.value"/>]</xsl:message> <xsl:variable name="rngRef.tmp.filtered" select="$rngRef.tmp1[rng:getDefine(.)[.//rng:attribute[@name = $att.name][count(*)=1][rng:value = $att.value]]]" as="element()*"/> <xsl:choose> <xsl:when test="count($rngRef.tmp.filtered) != 0"> <xsl:sequence select="$rngRef.tmp.filtered"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="$rngRef.tmp1"/> </xsl:otherwise> </xsl:choose> </xsl:when> <xsl:otherwise> <xsl:sequence select="$rngRef.tmp1"/> </xsl:otherwise> </xsl:choose> </xsl:when> <xsl:otherwise> <xsl:sequence select="$rngRef.tmp1"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:message use-when="false()">DEBUG <xsl:value-of select="$refName"/> : COUNT <xsl:value-of select="count($rngRef.tmp2)"/></xsl:message> <xsl:message use-when="false()"> <xsl:for-each select="$rngRef.tmp2/rng:getDefine(.)"> <xsl:value-of select="@name"/> : <xsl:value-of select="count(.//attribute)"/> attributes (dont <xsl:value-of select="count(.//attribute[.//value])"/> avec value) </xsl:for-each> </xsl:message> <xsl:variable name="rngRef.min.static-attributes" select="(min($rngRef.tmp2/rng:getDefine(.)/count(.//attribute[.//value])), 0)[1]" as="xs:integer"/> <xsl:variable name="rngRef" select="($rngRef.tmp2)[rng:getDefine(.)/count(.//attribute[.//value]) = $rngRef.min.static-attributes]" as="element(rng:ref)*"/> <!--($rngRef)[last()] may be empty, keep the last of $rngRef.tmp2 if so--> <xsl:sequence select="(($rngRef)[1], $rngRef.tmp2[1])[1]"/> <!--<xsl:sequence select="$rngRef.tmp2[1]"/>--> <xsl:if test="count($rngRef) gt 1"> <xsl:message>[WARNING][rng:getRef()] <xsl:value-of select="count($rngRef)"/> rng:ref name="<xsl:value-of select="$refName"/>" found within <xsl:value-of select="els:get-xpath($rngElement)"/>, fallback on last occurence</xsl:message> <!--FIXME : ce cas de figure est tout à fait possible quand il y a un choose, ou un mixed, il faut pour cela parser le XML en même temps pour savoir où on est => utiliser une vraie librairie RNG !--> </xsl:if> </xsl:function> <!--2 args signature of rng:getRefByElementName--> <xsl:function name="rng:getRefByElementName" as="element(rng:ref)?"> <xsl:param name="rngElement" as="element(rng:element)"/> <xsl:param name="refName" as="xs:string"/> <xsl:sequence select="rng:getRefByElementName($rngElement, $refName, ())"/> </xsl:function> <xsl:function name="rng:getAttributeDataType" as="xs:string?"> <xsl:param name="rngElement" as="element(rng:element)"/> <xsl:param name="attName" as="xs:string"/> <xsl:sequence select="$rngElement//attribute[@name = $attName]/data/@type"/> </xsl:function> <!--===========================================================--> <!-- rng:mergeIdenticalDefine --> <!--===========================================================--> <xsl:template match="grammar" mode="rng:mergeIdenticalDefine"> <xsl:message>[INFO] rng:mergeIdenticalDefine on <xsl:value-of select="local-name()"/></xsl:message> <xsl:variable name="step" as="document-node()"> <xsl:document> <xsl:apply-templates select="." mode="rng:mergeIdenticalDefine.step1"/> </xsl:document> </xsl:variable> <xsl:apply-templates select="$step" mode="rng:mergeIdenticalDefine.step2"/> </xsl:template> <!-- === STEP1 === --> <xsl:template match="define" mode="rng:mergeIdenticalDefine.step1"> <xsl:variable name="current.define" select="." as="element(define)"/> <xsl:copy copy-namespaces="no"> <xsl:apply-templates select="@*" mode="#current"/> <xsl:variable name="is-identical-with" select="parent::grammar/define[deep-equal(rng:normalizeDefine4Comparing(.), rng:normalizeDefine4Comparing($current.define))]/@name" as="xs:string*"/> <!--[not(. is $current.define)]--> <xsl:if test="count($is-identical-with) gt 1"> <xsl:attribute name="is-identical-with" select="$is-identical-with"/> </xsl:if> <xsl:apply-templates select="node()" mode="#current"/> </xsl:copy> </xsl:template> <!-- === STEP2 === --> <!--keep only the first define when they are multiple identical occurence of it--> <xsl:template match="define[preceding-sibling::define[@is-identical-with = current()/@is-identical-with]]" mode="rng:mergeIdenticalDefine.step2"/> <!--redirect every ref to the first occurence of the multiple define--> <xsl:template match="ref[rng:getDefine(.)/@is-identical-with]" mode="rng:mergeIdenticalDefine.step2"> <xsl:variable name="self" select="." as="element(ref)"/> <xsl:variable name="define" select="rng:getDefine(.)" as="element(define)"/> <xsl:variable name="define.is-identical-with.token" select="tokenize($define/@is-identical-with, '\s+')" as="xs:string+"/> <xsl:variable name="identical.define" select="for $name in $define.is-identical-with.token return key('rng:getDefineByName', $name, $self/root())" as="element(define)+"/> <xsl:copy copy-namespaces="no"> <xsl:copy-of select="@*"/> <xsl:attribute name="name" select="$identical.define[1]/@name"/> </xsl:copy> </xsl:template> <!--delete tmp attribute--> <xsl:template match="@is-identical-with" mode="rng:mergeIdenticalDefine.step2"/> <!--default copy--> <xsl:template match="node() | @*" mode="rng:mergeIdenticalDefine.step1 rng:mergeIdenticalDefine.step2"> <xsl:copy copy-namespaces="no"> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> <xsl:function name="rng:normalizeDefine4Comparing" as="element(define)"> <xsl:param name="define" as="element(define)"/> <define> <!--@name must be deleted for comparaison--> <xsl:apply-templates select="$define/*" mode="rng:normalizeDefine4Comparing"/> </define> </xsl:function> <xsl:template match="*" mode="rng:normalizeDefine4Comparing"> <xsl:copy copy-namespaces="no"> <xsl:for-each select="@*"> <xsl:sort/> <xsl:copy-of select="."/> </xsl:for-each> <xsl:apply-templates select="*" mode="#current"> <!--<xsl:sort/> NO, it would change the define--> </xsl:apply-templates> </xsl:copy> </xsl:template> <!--Sorting on "choice" is ok--> <xsl:template match="choice" mode="rng:normalizeDefine4Comparing"> <xsl:copy copy-namespaces="no"> <xsl:for-each select="@*"> <xsl:sort/> <xsl:copy-of select="."/> </xsl:for-each> <xsl:apply-templates select="*" mode="#current"> <xsl:sort/> </xsl:apply-templates> </xsl:copy> </xsl:template> <!--===========================================================--> <!-- rng:clean --> <!--===========================================================--> <!--nettoyage du rng (après manip manuelle dessus) pour le garder valide on espère--> <!--Attention le / est très important, on initie rng:clean sur un document-node(), mais ensuite l'apply-template ci-dessous ne repasse pas par là car on travail avec element(grammar) ci-dessous, ce qui évite une boucle récursive infinie--> <xsl:template match="/grammar" mode="rng:clean"> <xsl:param name="rng:clean_mergeIdenticalDefines" select="false()" as="xs:boolean"/> <xsl:message>[INFO] rng:clean on <xsl:value-of select="local-name()"/></xsl:message> <xsl:variable name="step" as="element(grammar)"> <xsl:call-template name="rng:deleteOrphansDefine"> <xsl:with-param name="tree" select="."/> </xsl:call-template> </xsl:variable> <xsl:variable name="step" as="element(grammar)"> <xsl:call-template name="rng:deleteEmptyStructuralInstructionInDataModel"> <xsl:with-param name="tree" select="$step"/> </xsl:call-template> </xsl:variable> <xsl:variable name="step" as="element(grammar)"> <xsl:apply-templates select="$step" mode="#current"/> </xsl:variable> <xsl:choose> <xsl:when test="$rng:clean_mergeIdenticalDefines"> <xsl:apply-templates select="$step" mode="rng:mergeIdenticalDefine"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="$step"/> </xsl:otherwise> </xsl:choose> </xsl:template> <!--Déduplication sur ref dans les choice --> <xsl:template match="choice/ref" mode="rng:clean"> <xsl:if test="not(preceding-sibling::ref[@name = current()/@name])"> <xsl:next-match/> </xsl:if> </xsl:template> <!--Déduplication sur element dans les choice --> <xsl:template match="choice/element" mode="rng:clean"> <xsl:if test="not(preceding-sibling::element[deep-equal(., current())])"> <xsl:next-match/> </xsl:if> </xsl:template> <!--choice within choice is useless--> <xsl:template match="choice/choice" mode="rng:clean"> <xsl:apply-templates mode="#current"/> </xsl:template> <!--=== mode rng:deleteOrphansDefine ===--> <!--Suppression des <define> orphelins--> <!--Un template nommé pour initier la récursivité, puis passage dans un mode du même nom--> <xsl:template name="rng:deleteOrphansDefine"> <xsl:param name="tree" required="yes" as="element()"/> <xsl:param name="iteration" select="1" as="xs:integer"/> <xsl:message>[DEBUG][rng:deleteOrphansDefine] iteration = <xsl:value-of select="$iteration"/></xsl:message> <xsl:variable name="tree.new" as="element()"> <xsl:apply-templates select="$tree" mode="rng:deleteOrphansDefine"/> </xsl:variable> <xsl:choose> <!--Il reste des éléments vide après traitement, on repasse le traitement--> <xsl:when test="$tree.new//define[rng:isOrphanDefine(.)]"> <xsl:call-template name="rng:deleteOrphansDefine"> <xsl:with-param name="tree" select="$tree.new"/> <xsl:with-param name="iteration" select="$iteration + 1"/> </xsl:call-template> </xsl:when> <!--sinon, on renvoi l'arbre final--> <xsl:otherwise> <xsl:sequence select="$tree.new"/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="define[rng:isOrphanDefine(.)]" mode="rng:deleteOrphansDefine"> <xsl:message>[INFO][deleteOrphansDefine] Delete <xsl:value-of select="els:displayNode(.)"/></xsl:message> </xsl:template> <!--FIXME : ça ne permets pas de supprimer A qui reférence B qui référence A => il faudrait revoir l'algo global => partit du start et aller jusqu'à la fin du modèle en suivant les ref En déduire une liste de define utiles et supprimer tous les autres !--> <xsl:function name="rng:isOrphanDefine" as="xs:boolean"> <xsl:param name="define" as="element(define)"/> <!--Le 3e arg de key() doit $etre un document-node() : on force la chose puisque tree est un element()--> <xsl:variable name="virtual.root" as="document-node()"> <xsl:document> <xsl:sequence select="$define/root()"/> </xsl:document> </xsl:variable> <!--Il n'existe pas de référence à ce define qui ne soit pas déjà dans ce define (cas de ref circulaire)--> <xsl:sequence select="not(exists( key('rng:getRefByName', $define/@name, $virtual.root)[not(ancestor::*[. is $define])] ))"/> </xsl:function> <!--=== mode rng:deleteEmptyStructuralInstructionInDataModel ===--> <!--Un template nommé pour initier la récursivité, puis passage dans un mode du même nom--> <xsl:template name="rng:deleteEmptyStructuralInstructionInDataModel"> <xsl:param name="tree" required="yes" as="element()"/> <xsl:param name="iteration" select="1" as="xs:integer"/> <!--<xsl:message>[DEBUG][rng:deleteEmptyStructuralInstructionInDataModel] iteration = <xsl:value-of select="$iteration"/></xsl:message>--> <xsl:variable name="tree.new" as="element()"> <xsl:apply-templates select="$tree" mode="rng:deleteEmptyStructuralInstructionInDataModel"/> </xsl:variable> <xsl:choose> <!--Il reste des éléments vide après traitement, on repasse le traitement--> <xsl:when test="$tree.new//*[rng:isEmptyStructuralInstructionInDataModel(.)]"> <xsl:call-template name="rng:deleteEmptyStructuralInstructionInDataModel"> <xsl:with-param name="tree" select="$tree.new"/> <xsl:with-param name="iteration" select="$iteration + 1"/> </xsl:call-template> </xsl:when> <!--sinon, on renvoi l'arbre final--> <xsl:otherwise> <xsl:sequence select="$tree.new"/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="*[rng:isEmptyStructuralInstructionInDataModel(.)]" mode="rng:deleteEmptyStructuralInstructionInDataModel"> <!--<xsl:message>[INFO] Delete <xsl:value-of select="els:displayNode(.)"/></xsl:message>--> </xsl:template> <!-- === FONCTIONS utile au mode rng:clean === --> <!--Tous les éléments qui servent à construire le data model, à l'exclusion de ce qui forme le contenu (<attribute/>, <element/>, <text/>, ...) FIXME : quid des ref ?--> <xsl:function name="rng:isStructuralInstructionInDataModel" as="xs:boolean"> <xsl:param name="e" as="element()"/> <xsl:sequence select=" namespace-uri($e) = 'http://relaxng.org/ns/structure/1.0' and local-name($e) = ('optional', 'zeroOrMore', 'oneOrMore', 'group', 'interleave', 'choice')"/> </xsl:function> <xsl:function name="rng:isEmptyStructuralInstructionInDataModel" as="xs:boolean"> <xsl:param name="e" as="element()"/> <xsl:sequence select="rng:isStructuralInstructionInDataModel($e) and not($e/*)"/> </xsl:function> <!--copie par défaut dans le mode rng:clean--> <xsl:template match="node() | @*" mode="rng:clean rng:deleteEmptyStructuralInstructionInDataModel rng:deleteOrphansDefine"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> <!--===========================================================--> <!-- rng:reorder --> <!--===========================================================--> <xd:doc> <xd:desc> <xd:p>mode="rng:reorder"</xd:p> <xd:p>Réordonne les define d'un fichier RNG simplifié, en se basant sur le nom de l'élément</xd:p> <xd:p>Si 2 éléments ont le même nom, l'ordre pourra se faire sur la valeur d'un attribut, par défaut @class</xd:p> </xd:desc> </xd:doc> <!--FIXME : impossible d'appeler cette xsl avec initial mode = rng:reorder avec saxon il semble que le nom du mode ne peut pas être préfixé--> <xsl:param name="rng:reorder_renameDefineRef" select="true()" as="xs:boolean"/> <xsl:template match="/" mode="rng:reorder"> <xsl:param name="rng:reorder_byAttributeName" select="'class'" as="xs:string?"/> <xsl:param name="rng:reorder_addRootNamespaces" as="node()*"> <!--NB : http://markmail.org/message/gfmje533lawarcsg--> <!--<xsl:namespace name="rng">http://relaxng.org/ns/structure/1.0</xsl:namespace>--> </xsl:param> <xsl:apply-templates mode="#current"> <xsl:with-param name="rng:reorder_byAttributeName" select="$rng:reorder_byAttributeName"/> <xsl:with-param name="rng:reorder_addGrammarNamespaces" select="$rng:reorder_addRootNamespaces"/> </xsl:apply-templates> </xsl:template> <xsl:template match="/grammar" mode="rng:reorder"> <xsl:param name="rng:reorder_byAttributeName" as="xs:string?"/> <xsl:param name="rng:reorder_addGrammarNamespaces" as="node()*"/> <xsl:message>[INFO] rng:reorder sur <xsl:value-of select="local-name()"/></xsl:message> <xsl:variable name="step" as="document-node()"> <xsl:document> <xsl:copy copy-namespaces="yes"> <xsl:copy-of select="$rng:reorder_addGrammarNamespaces"/> <xsl:apply-templates select="@*" mode="#current"/> <xsl:apply-templates select="start" mode="#current"/> <xsl:apply-templates select="define" mode="#current"> <!--when converting dtd2rng trang.jar generates <define name="attlist.elementName">, so we keep this next to the define <define name="elementName"> => Not really usefull because in this case trang.jar already order defines in a good way !--> <xsl:sort select="concat( (element[1]/@name, element[1]/name)[1]/lower-case(replace(., '^attlist\.', '')), '_', element[1]//attribute[@name = $rng:reorder_byAttributeName]/value/text() )"/> </xsl:apply-templates> </xsl:copy> </xsl:document> </xsl:variable> <xsl:choose> <xsl:when test="$rng:reorder_renameDefineRef"> <xsl:apply-templates select="$step" mode="rng:renameDefineAndRefByElementNameAndOrder"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="$step"/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="node() | @*" mode="rng:reorder"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> <xd:doc> <xd:desc> <xd:p>Rename define and ref by element name and order in the rng document</xd:p> </xd:desc> </xd:doc> <xsl:template match="/grammar" mode="rng:renameDefineAndRefByElementNameAndOrder"> <xsl:message>[INFO] rng:renameDefineAndRefByElementNameAndOrder sur <xsl:value-of select="local-name()"/></xsl:message> <xsl:next-match/> </xsl:template> <!--Exception : here we accept an non simplified RNG schema, so we add a filter on define[element]--> <xsl:template match="define[element]/@name" mode="rng:renameDefineAndRefByElementNameAndOrder"> <xsl:variable name="define" select="parent::define" as="element()"/> <xsl:variable name="elementName" select="($define/element[1]/@name, $define/element[1]/name)[1]" as="xs:string"/> <xsl:variable name="count" select="count($define/preceding-sibling::define[(element[1]/@name, element[1]/name)[1] = $elementName])" as="xs:integer"/> <xsl:attribute name="{name(.)}"> <xsl:choose> <xsl:when test="$count = 0"> <xsl:sequence select="$elementName"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="concat($elementName, '_', $count + 1)"/> </xsl:otherwise> </xsl:choose> </xsl:attribute> </xsl:template> <xsl:template match="ref/@name" mode="rng:renameDefineAndRefByElementNameAndOrder"> <xsl:variable name="ref" select="parent::ref" as="element()"/> <xsl:apply-templates select="rng:getDefine($ref)/@name" mode="#current"/> </xsl:template> <xsl:template match="node() | @*" mode="rng:renameDefineAndRefByElementNameAndOrder"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> <!--===========================================================--> <!-- rng:getXpathFromDataModel --> <!--===========================================================--> <!--/!\ WARNING : please use this function only for testing, it's just a Proof Of Concept, but this is really greedy ! PLEASE NEVER USE IT IN REAL CODE ! --> <xd:doc> <xd:desc> <xd:p>Returns a list of xpath that matches a rng:element definition in the schema</xd:p> </xd:desc> <xd:param name="element">Any rng:element in a simplified RNG schema</xd:param> <xd:param name="xpath.level">Indicate which level of xpath to go up from the element</xd:param> <xd:return>A list of xpath</xd:return> </xd:doc> <xsl:function name="rng:getXpathFromDataModel" as="xs:string*"> <xsl:param name="element" as="element(rng:element)"/> <xsl:param name="xpath.level" as="xs:integer"/> <xsl:for-each select="distinct-values(rng:getXpathFromDataModel_debug($element, $xpath.level)/descendant-or-self::xpath/@value)"> <xsl:sort/> <xsl:sequence select="."/> </xsl:for-each> </xsl:function> <!--1 arg signature--> <xsl:function name="rng:getXpathFromDataModel" as="xs:string*"> <xsl:param name="element" as="element(rng:element)"/> <xsl:sequence select="rng:getXpathFromDataModel($element, -1)"/><!-- "-1" means infinite--> </xsl:function> <xsl:function name="rng:getXpathFromDataModel_debug" as="element(ref)*"> <xsl:param name="element" as="element(rng:element)"/> <xsl:param name="xpath.level" as="xs:integer"/> <xsl:apply-templates select="$element/parent::define" mode="rng:backToStartXpath"> <xsl:with-param name="xpath.maxLevel" select="$xpath.level" tunnel="yes"/> <xsl:with-param name="xpath.level" select="1"/> <!--init--> </xsl:apply-templates> </xsl:function> <xsl:template match="define" mode="rng:backToStartXpath"> <xsl:param name="reverse.xpath" as="xs:string?"/> <!--empty at first iteration--> <xsl:param name="ref.iterated" as="element(rng:ref)*"/> <xsl:param name="xpath.level" required="yes" as="xs:integer"/> <xsl:variable name="element" select="element" as="element(rng:element)"/> <xsl:variable name="refToThis" select="ancestor::grammar//ref[rng:getDefine(.) is current()]" as="element(rng:ref)*"/> <xsl:variable name="refToThis.notCircular" select="$refToThis[not(ancestor::define is current())]" as="element(rng:ref)*"/> <xsl:choose> <xsl:when test="$refToThis.notCircular intersect $ref.iterated"> <stop cause="circularRef"/> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="$refToThis.notCircular" mode="#current"> <xsl:with-param name="reverse.xpath" as="xs:string"> <xsl:choose> <!--init on first iteration--> <xsl:when test="count($reverse.xpath) = 0"> <xsl:value-of select="$element/@name"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="concat($reverse.xpath, '\', $element/@name)"/> </xsl:otherwise> </xsl:choose> </xsl:with-param> <xsl:with-param name="ref.iterated" select="$ref.iterated"/> <xsl:with-param name="xpath.level" select="$xpath.level + 1"/> </xsl:apply-templates> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="ref" mode="rng:backToStartXpath"> <xsl:param name="reverse.xpath" as="xs:string"/> <xsl:param name="ref.iterated" as="element(rng:ref)*"/> <xsl:param name="xpath.level" as="xs:integer"/> <xsl:param name="xpath.maxLevel" as="xs:integer" tunnel="yes"/> <ref reverse.xpath="{$reverse.xpath}" current-ref="{@name}" current-define="{ancestor::define/@name}" xpath.level="{$xpath.level}"> <xsl:choose> <!--<xsl:when test="self::ref intersect $ref.iterated"> <xsl:message>[STOP] on est déjà passé par le ref name="<xsl:value-of select="@name"/>" dans le define "<xsl:value-of select="ancestor::define/@name"/>"</xsl:message> <xsl:variable name="reverse.xpath.tokenized" select="tokenize($reverse.xpath, '\\')" as="xs:string*"/> <xsl:variable name="reverse.xpath.tokenized.reverse" select="reverse($reverse.xpath.tokenized)" as="xs:string*"/> <xpath debug="w1" value="{concat('//', string-join($reverse.xpath.tokenized.reverse, '/'))}"/> </xsl:when>--> <xsl:when test="ancestor::start"> <xsl:variable name="reverse.xpath.tokenized" select="tokenize($reverse.xpath, '\\')" as="xs:string*"/> <xsl:variable name="reverse.xpath.tokenized.reverse" select="reverse($reverse.xpath.tokenized)" as="xs:string*"/> <xpath debug="w2" value="{concat('/', string-join($reverse.xpath.tokenized.reverse, '/'))}"/> </xsl:when> <xsl:when test="($xpath.maxLevel gt -1) and ($xpath.level gt $xpath.maxLevel)"> <stop cause="maxLevel" xpath.level="{$xpath.level}"/> <xsl:variable name="reverse.xpath.tokenized" select="tokenize($reverse.xpath, '\\')" as="xs:string*"/> <xsl:variable name="reverse.xpath.tokenized.reverse" select="reverse($reverse.xpath.tokenized)" as="xs:string*"/> <xpath debug="w3" value="{string-join($reverse.xpath.tokenized.reverse, '/')}"/> </xsl:when> <xsl:when test="ancestor::define"> <xsl:apply-templates select="ancestor::define" mode="#current"> <xsl:with-param name="reverse.xpath" select="$reverse.xpath" as="xs:string"/> <xsl:with-param name="ref.iterated" select="($ref.iterated, .)" as="element(rng:ref)*"/> <xsl:with-param name="xpath.level" select="$xpath.level"/> </xsl:apply-templates> </xsl:when> <xsl:otherwise> <xsl:message terminate="yes">[ERROR] no ancestor define for <xsl:value-of select="els:get-xpath(.)"/></xsl:message> </xsl:otherwise> </xsl:choose> </ref> </xsl:template> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" xmlns:xslLib="http://www.lefebvre-sarrut.eu/ns/els/xslLib" xmlns:cals2html="http://www.lefebvre-sarrut.eu/ns/els/xslLib/cals2html" xmlns:cals="http://docs.oasis-open.org/ns/oasis-exchange/table" xmlns:html="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml" version="3.0" xpath-default-namespace="http://docs.oasis-open.org/ns/oasis-exchange/table" exclude-result-prefixes="#all"> <xsl:import href="els-common.xsl"/> <xsl:import href="setXmlBase.xsl"/> <xsl:import href="removeXmlBase.xsl"/> <xsl:import href="normalizeCalsTable.xsl"/> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>Convert CALS Table to HTML table</xd:p> <xd:p>Each cals:table will be converted to an html:div, then each cals:tgroup will be converted to an html:table</xd:p> <xd:p>/!\ Cals element must be in cals namespace before proceding, other elements will be copied as is.</xd:p> </xd:desc> </xd:doc> <!--PARAMETERS--> <!--common--> <xsl:param name="xslLib:cals2html.log.uri" select="resolve-uri('log/', base-uri())" as="xs:string"/> <xsl:param name="xslLib:cals2html.debug" select="false()" as="xs:boolean"/> <!--structure--> <xsl:param name="xslLib:cals2html.html-version" select="5" as="xs:double"/> <!--4 or 5 for example--> <xsl:param name="xslLib:cals2html.use-style-insteadOf-class" select="true()" as="xs:boolean"/> <xsl:param name="xslLib:cals2html-keep-unmatched-attributes" select="false()" as="xs:boolean"/> <xsl:param name="xslLib:cals2html-unmatched-attributes-prefix" select="'data-cals2html-'" as="xs:string"/> <xsl:param name="xslLib:cals2html.compute-column-width-as-width-attribute" select="true()" as="xs:boolean"/> <!--@width is used for html4 output--> <xsl:param name="xslLib:cals2html.compute-column-width-within-colgroup" select="true()" as="xs:boolean"/> <!--If the number of columns is greater than $nb-cols-max-before-font-reduction then the font needs to be reduced--> <xsl:param name="xslLib:cals2html.nb-cols-max-before-font-reduction" select="8" as="xs:integer"/> <xsl:param name="xslLib:cals2html.nb-cols-max-before-large-font-reduction" select="14" as="xs:integer"/> <!--default colsep/rowsep--> <xsl:param name="xslLib:cals2html.default-colsep" select="'yes'" as="xs:string"/> <xsl:param name="xslLib:cals2html.default-rowsep" select="'yes'" as="xs:string"/> <!--default align/valign--> <xsl:param name="xslLib:cals2html.default-tgroup-align" select="'left'" as="xs:string"/> <xsl:param name="xslLib:cals2html.default-td-align" select="'left'" as="xs:string"/><!--default browser value--> <xsl:param name="xslLib:cals2html.default-th-align" select="'center'" as="xs:string"/><!--default browser value--> <xsl:param name="xslLib:cals2html.default-tgroup-valign" select="'middle'" as="xs:string"/> <xsl:param name="xslLib:cals2html.default-td-valign" select="'middle'" as="xs:string"/><!--default browser value--> <xsl:param name="xslLib:cals2html.default-th-valign" select="'middle'" as="xs:string"/><!--default browser value--> <!--==============================================================================================================================--> <!-- INIT --> <!--==============================================================================================================================--> <xsl:template match="/"> <xsl:apply-templates select="/" mode="xslLib:cals2html"/> </xsl:template> <!--==============================================================================================================================--> <!-- DRIVER --> <!--==============================================================================================================================--> <xsl:template match="/" mode="xslLib:cals2html"> <!--STEP0 : set xml:base to init multi-step--> <xsl:variable name="step" as="document-node()"> <xsl:document> <xsl:apply-templates select="." mode="xslLib:setXmlBase"/> </xsl:document> </xsl:variable> <!--STEP1 : normalize cals table--> <xsl:variable name="step" as="document-node()"> <xsl:document> <xsl:apply-templates select="$step" mode="xslLib:normalizeCalsTable"/> </xsl:document> </xsl:variable> <xsl:if test="$xslLib:cals2html.debug"> <xsl:variable name="step.log.uri" select="resolve-uri('cals2html.step1.xml', $xslLib:cals2html.log.uri)" as="xs:anyURI"/> <xsl:message>[INFO] writing <xsl:value-of select="$step.log.uri"/></xsl:message> <xsl:result-document href="{$step.log.uri}"> <xsl:sequence select="$step"/> </xsl:result-document> </xsl:if> <!--STEP2 : cals2html.main--> <xsl:variable name="step" as="document-node()"> <xsl:document> <xsl:apply-templates select="$step" mode="xslLib:cals2html.main"/> </xsl:document> </xsl:variable> <xsl:if test="$xslLib:cals2html.debug"> <xsl:variable name="step.log.uri" select="resolve-uri('cals2html.step2.xml', $xslLib:cals2html.log.uri)" as="xs:anyURI"/> <xsl:message>[INFO] writing <xsl:value-of select="$step.log.uri"/></xsl:message> <xsl:result-document href="{$step.log.uri}"> <xsl:sequence select="$step"/> </xsl:result-document> </xsl:if> <!--STEP3 : convert class2style--> <xsl:variable name="step" as="document-node()"> <xsl:choose> <xsl:when test="$xslLib:cals2html.use-style-insteadOf-class"> <xsl:document> <xsl:apply-templates select="$step" mode="xslLib:cals2html.class2style"/> </xsl:document> </xsl:when> <xsl:otherwise> <xsl:sequence select="$step"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:if test="$xslLib:cals2html.debug"> <xsl:variable name="step.log.uri" select="resolve-uri('cals2html.step3.xml', $xslLib:cals2html.log.uri)" as="xs:anyURI"/> <xsl:message>[INFO] writing <xsl:value-of select="$step.log.uri"/></xsl:message> <xsl:result-document href="{$step.log.uri}"> <xsl:sequence select="$step"/> </xsl:result-document> </xsl:if> <!--FINALY--> <xsl:apply-templates select="$step" mode="xslLib:removeXmlBase"/> </xsl:template> <!--==============================================================================================================================--> <!-- STEP 1 --> <!--==============================================================================================================================--> <!--see normalizeCalsTable.xsl--> <!--==============================================================================================================================--> <!-- STEP 2 : cal2html.main --> <!--==============================================================================================================================--> <!-- TABLE --> <!-- CALS MODEL : table ::= title, tgroup+ --> <!-- Inherit rowsep : if @rowsep undefined then inherit it, else use it--> <xsl:template match="table" mode="xslLib:cals2html.main"> <!-- https://www.oasis-open.org/specs/tm9901.html#AEN282 : "All tgroups of a table shall have the same width, so the table frame can surround them uniformly" FIXME => adding a table container to ensure this ? (CHAINEXML-872)--> <div class="cals_table"> <!--@id | @tabstyle | @orient | @pgwide | @shortentry | @ tocentry--> <xsl:apply-templates select="@*" mode="xslLib:cals2html.attributes"/> <xsl:apply-templates mode="#current"/> </div> </xsl:template> <xsl:template match="caption" mode="xslLib:cals2html.main"> <!-- no operation : everything has already been put within html:table/html:caption element --> </xsl:template> <!-- TGROUP : start Html Table structure --> <!-- CALS MODEL : tgroup ::= colspec+, thead?, tbody--> <xsl:template match="tgroup" mode="xslLib:cals2html.main"> <table> <!--attributes that doesn't generate @style or @class like : ../@orient | @id ?--> <xsl:apply-templates select="@*" mode="xslLib:cals2html.attributes"/> <xsl:variable name="class.tmp" as="xs:string*"> <xsl:text>cals_tgroup</xsl:text> <!--cals:table/@frame ::= none | top | bottom | topbot | sides | all default is "all"--> <xsl:value-of select="concat('cals_frame-', (../@frame, 'all')[1])"/> </xsl:variable> <xsl:if test="not(empty($class.tmp))"> <xsl:attribute name="class" select="string-join($class.tmp, ' ')"/> </xsl:if> <xsl:variable name="style.tmp" as="xs:string*"> <xsl:if test="../@pgwide = '1'"> <xsl:text>width:100%</xsl:text> </xsl:if> </xsl:variable> <xsl:if test="not(empty($style.tmp))"> <xsl:attribute name="style" select="string-join($style.tmp, ' ')"/> </xsl:if> <xsl:if test="$xslLib:cals2html.compute-column-width-within-colgroup"> <colgroup> <xsl:variable name="colspec" select="colspec" as="element(colspec)*"/> <xsl:for-each select="colspec"> <col> <xsl:call-template name="xslLib:cals2html.add-column-width"> <xsl:with-param name="colspec-list-for-total-width" select="$colspec" as="element(colspec)*"/> <xsl:with-param name="colspec-list-for-current-width" select="." as="element(colspec)*"/> </xsl:call-template> </col> </xsl:for-each> </colgroup> </xsl:if> <xsl:if test="normalize-space(@cols) != '' and not(normalize-space(@cols) castable as xs:integer)"> <xsl:message terminate="no">[ERROR][xslLib:cals2html] @cols="<xsl:value-of select="@cols"/>" is not an integer</xsl:message> </xsl:if> <xsl:apply-templates mode="xslLib:cals2html.main" select="thead"/> <xsl:if test="tfoot"> <tfoot> <xsl:apply-templates select="tfoot" mode="#current"/> </tfoot> </xsl:if> <xsl:apply-templates select="* except (thead, tfoot) (:head and foot has already been processed :)" mode="#current"/> </table> </xsl:template> <!-- Table Head --> <!-- CALS MODEL : thead ::= colspec*,row+ --> <xsl:template match="thead" mode="xslLib:cals2html.main"> <thead> <xsl:apply-templates mode="#current"/> </thead> </xsl:template> <xsl:template match="colspec" mode="xslLib:cals2html.main"> <!-- no operation --> </xsl:template> <xsl:template match="spanspec" mode="xslLib:cals2html.main"> <!-- no operation --> </xsl:template> <!-- Table Foot --> <!-- CALS MODEL : tfoot ::= colspec*,row+ --> <xsl:template match="tfoot" mode="xslLib:cals2html.main"> <xsl:apply-templates select="*" mode="#current"/> </xsl:template> <!-- Table bocy --> <!-- CALS MODEL : tbody ::= row+--> <xsl:template match="tbody" mode="xslLib:cals2html.main"> <tbody> <xsl:apply-templates mode="#current"/> </tbody> </xsl:template> <!-- Table Row --> <!-- CALS MODEL : row ::= entry+ --> <xsl:template match="row" mode="xslLib:cals2html.main"> <tr> <xsl:apply-templates select="@*" mode="xslLib:cals2html.attributes"/> <xsl:variable name="class.tmp" as="xs:string*"> <!--<xsl:if test="$xslLib:cals2html.add-odd-even-class"> <xsl:value-of select="if (count(preceding-sibling::row) mod 2 = 0) then 'cals_odd' else 'cals_even'"/> </xsl:if>--> </xsl:variable> <xsl:if test="not(empty($class.tmp))"> <xsl:attribute name="class" select="string-join($class.tmp, ' ')"/> </xsl:if> <xsl:variable name="style.tmp" as="xs:string*"> <!--<xsl:sequence select="@bgcolor"/>--> </xsl:variable> <xsl:if test="not(empty($style.tmp))"> <xsl:attribute name="style" select="string-join($style.tmp, ' ')"/> </xsl:if> <xsl:apply-templates mode="#current"/> </tr> </xsl:template> <!-- Table Cell --> <!-- CALS MODEL : entry ::= "global model dependent"--> <xsl:template match="entry" mode="xslLib:cals2html.main"> <xsl:variable name="nb-cols" select="ancestor::tgroup[1]/@cols[. castable as xs:integer]" as="xs:integer?"/> <xsl:variable name="entry" select="self::*" as="element(entry)"/> <xsl:variable name="current-tgroup" select="ancestor::tgroup[1]" as="element()"/> <xsl:variable name="current-colspec-list" as="element(colspec)*"> <xsl:choose> <!-- Firts consider @namestart/nameend --> <xsl:when test="@namest and @nameend"> <xsl:variable name="namest.colspec" select="$current-tgroup/colspec[@colname = current()/@namest]" as="element()*"/> <xsl:variable name="nameend.colspec" select="$current-tgroup/colspec[@colname = current()/@nameend]" as="element()*"/> <xsl:choose> <xsl:when test="count($namest.colspec) != 1"> <xsl:message terminate="no">[ERROR][cals2html.xsl] No colspec exists in the current tgroup with @colname equals to current @namest="<xsl:value-of select="@namest"/>"</xsl:message> </xsl:when> <xsl:when test="count($nameend.colspec) != 1"> <xsl:message terminate="no">[ERROR][cals2html.xsl] No colspec exists in the current tgroup with @colname equals to current @nameend="<xsl:value-of select="@nameend"/>"</xsl:message> </xsl:when> <xsl:otherwise> <!--FIXME : a-t-on vraiment besoin de passer par colnum, ne pourrait-on pas prendre les colspec situés entre namest.colspec et nameend.colspec dans le xml ?--> <xsl:variable name="colnumst" select="xslLib:cals2html.get-colnum($entry, $namest.colspec)" as="xs:integer"/> <xsl:variable name="colnumend" select="xslLib:cals2html.get-colnum($entry, $nameend.colspec)" as="xs:integer"/> <xsl:sequence select="$current-tgroup/colspec [xslLib:cals2html.get-colnum($entry, .) ge $colnumst] [xslLib:cals2html.get-colnum($entry, .) le $colnumend]"/> </xsl:otherwise> </xsl:choose> </xsl:when> <!--If one of the following/preceding entry has a namest/nameend colum, then consider the current colspec *from* this point, example : <tgroup> <colspec ... colname="c1"/> <colspec ... colname="c2"/> <colspec ... colname="c3"/> <colspec ... colname="c4"/> <colspec ... colname="c5"/> <colspec ... colname="c6"/> <tbody> <row> <entry ... /> => c1 <entry ... /> => c2 <entry ... namest="c3" nameend="c4"/> => c3/c4 <entry ... /> => c5 <entry ... /> => c6 </row> </tbody> </tgroup> --> <!--There is no current namest/nameend, look if there is a preceding entry with a "nameend" column, if so then use the next colspec by position--> <xsl:when test="preceding-sibling::entry[@nameend]"> <xsl:variable name="psib1.entry-nameend" select="preceding-sibling::entry[@nameend][1]" as="element()"/> <xsl:variable name="distance" select="count(preceding-sibling::entry[. >> $psib1.entry-nameend]) + 1" as="xs:integer"/> <xsl:sequence select="$current-tgroup/colspec[@colname = $psib1.entry-nameend/@nameend]/following-sibling::colspec[$distance]"/> </xsl:when> <!--There is no namest/nameend, look if there is a following entry with a "namest" column, if so then use the preceding colspec by position--> <xsl:when test="following-sibling::entry[@namest]"> <xsl:variable name="fsib1.entry-namest" select="following-sibling::entry[@namest][1]" as="element()"/> <xsl:variable name="distance" select="count(following-sibling::entry[. << $fsib1.entry-namest]) + 1" as="xs:integer"/> <xsl:sequence select="$current-tgroup/colspec[@colname = $fsib1.entry-namest/@namest]/preceding-sibling::colspec[$distance]"/> </xsl:when> <!--There is no namest/nameend at all in the current row, let's consider @colname--> <xsl:when test="@colname"> <xsl:variable name="colname.colspec" select="$current-tgroup/colspec[@colname = current()/@colname]" as="element()*"/> <xsl:if test="count($colname.colspec) != 1"> <xsl:message terminate="no">[ERROR][cals2html.xsl] No colspec exists in the current tgroup with @colname equals to current @colname="<xsl:value-of select="@colname"/>"</xsl:message> </xsl:if> <xsl:sequence select="$colname.colspec"/> </xsl:when> <!--Finaly consider position--> <xsl:when test="position() > 1 and ../entry[@colname]"> <xsl:message>[ERROR][cals2html.xsl] Unable to get colspec for this entry. @colname might be missing ? (<xsl:value-of select="els:getFileName(string(base-uri()))"/> : <xsl:sequence select="els:get-xpath(.)"/>)</xsl:message> </xsl:when> <xsl:when test="position() > 1 and ../entry[(position() lt last() and (@namest and @nameend))]"> <xsl:message>[ERROR][cals2html.xsl] Unable to get colspec for this entry. Too much columns (<xsl:value-of select="els:getFileName(string(base-uri()))"/> : <xsl:sequence select="els:get-xpath(.)"/>)</xsl:message> </xsl:when> <xsl:otherwise> <xsl:variable name="pos" select="count(preceding-sibling::entry) + 1" as="xs:integer"/> <xsl:sequence select="$current-tgroup/colspec[$pos]"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="colsep-current" as="xs:string"> <xsl:choose> <xsl:when test="@colsep"> <xsl:value-of select="@colsep"/> </xsl:when> <!-- FIXME : que se passe-t-il lors d'un colspan ? a priori c'est le namest qui gagne--> <xsl:when test="$current-colspec-list[1]/@colsep"> <xsl:value-of select="$current-colspec-list[1]/@colsep"/> </xsl:when> <xsl:when test="ancestor::*/@colsep"> <xsl:value-of select="ancestor::*[@colsep][1]/@colsep"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$xslLib:cals2html.default-colsep"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="rowsep-current" as="xs:string"> <xsl:choose> <xsl:when test="@rowsep"> <xsl:value-of select="@rowsep"/> </xsl:when> <!-- FIXME : que se passe-t-il lors d'un colspan ? a priori c'est le namest qui gagne--> <xsl:when test="$current-colspec-list[1]/@rowsep"> <xsl:value-of select="$current-colspec-list[1]/@rowsep"/> </xsl:when> <xsl:when test="ancestor::*/@rowsep"> <xsl:value-of select="ancestor::*[@rowsep][1]/@rowsep"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$xslLib:cals2html.default-rowsep"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="align-current" as="xs:string"> <xsl:choose> <xsl:when test="@align"> <xsl:value-of select="@align"/> </xsl:when> <!-- FIXME : que se passe-t-il lors d'un colspan ? a priori c'est le namest qui gagne--> <xsl:when test="$current-colspec-list[1]/@align"> <xsl:value-of select="$current-colspec-list[1]/@align"/> </xsl:when> <xsl:when test="ancestor::*/@align"> <xsl:value-of select="ancestor::*[@align][1]/@align"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$xslLib:cals2html.default-tgroup-align"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="valign-current" as="xs:string"> <xsl:choose> <xsl:when test="@valign"> <xsl:value-of select="@valign"/> </xsl:when> <!-- FIXME : que se passe-t-il lors d'un colspan ? a priori c'est le namest qui gagne--> <xsl:when test="$current-colspec-list[1]/@valign"> <xsl:value-of select="$current-colspec-list[1]/@valign"/> </xsl:when> <xsl:when test="ancestor::*/@valign"> <xsl:value-of select="ancestor::*[@valign][1]/@valign"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$xslLib:cals2html.default-tgroup-valign"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="name" select="if(ancestor::thead) then ('th') else('td')" as="xs:string"/> <xsl:element name="{$name}"> <xsl:apply-templates select="@*" mode="xslLib:cals2html.attributes"/> <xsl:variable name="class.tmp" as="xs:string*"> <xsl:if test="$colsep-current != '0'"> <xsl:text>cals_colsep</xsl:text> </xsl:if> <xsl:if test="$rowsep-current != '0'"> <xsl:text>cals_rowsep</xsl:text> </xsl:if> <xsl:if test="$align-current != (if($name = 'td') then($xslLib:cals2html.default-td-align) else($xslLib:cals2html.default-th-align))"> <xsl:value-of select="concat('cals_align-', lower-case($align-current))"/> </xsl:if> <xsl:if test="$valign-current != (if($name = 'td') then($xslLib:cals2html.default-td-valign) else($xslLib:cals2html.default-th-valign))"> <xsl:value-of select="concat('cals_valign-', lower-case($valign-current))"/> </xsl:if> <xsl:if test="not(empty($nb-cols))"> <xsl:if test="$nb-cols > $xslLib:cals2html.nb-cols-max-before-font-reduction and $nb-cols lt $xslLib:cals2html.nb-cols-max-before-large-font-reduction"> <xsl:text>cals_table-font-reduction</xsl:text> </xsl:if> <xsl:if test="$nb-cols > $xslLib:cals2html.nb-cols-max-before-large-font-reduction"> <xsl:text>cals_table-max-font-reduction</xsl:text> </xsl:if> </xsl:if> </xsl:variable> <xsl:if test="not(empty($class.tmp))"> <xsl:attribute name="class" select="string-join($class.tmp, ' ')"/> </xsl:if> <xsl:variable name="style.tmp" as="xs:string*"> <!--<xsl:sequence select="@bgcolor"/>--> </xsl:variable> <xsl:if test="not(empty($style.tmp))"> <xsl:attribute name="style" select="string-join($style.tmp, ' ')"/> </xsl:if> <xsl:if test="not($xslLib:cals2html.compute-column-width-within-colgroup)"> <xsl:call-template name="xslLib:cals2html.add-column-width"> <xsl:with-param name="colspec-list-for-total-width" select="$current-tgroup/colspec" as="element(colspec)*"/> <xsl:with-param name="colspec-list-for-current-width" select="$current-colspec-list" as="element(colspec)*"/> </xsl:call-template> </xsl:if> <xsl:if test="count($current-colspec-list) > 1"> <xsl:attribute name="colspan" select="count($current-colspec-list)"/> </xsl:if> <xsl:if test="normalize-space(@morerows) != '' and normalize-space(@morerows) castable as xs:integer"> <xsl:attribute name="rowspan" select="xs:integer(@morerows) + 1"/> </xsl:if> <xsl:apply-templates mode="#current"/> </xsl:element> </xsl:template> <!-- === COMMON : STEP 2 === --> <!--Attributes to ignore here because they have already been processed before--> <xsl:template match="table/@frame | tgroup/@cols | entry/@namest | entry/@nameend | entry/@colname | entry/@morerows | cals:*/@rowsep | cals:*/@colsep | cals:*/@valign | cals:*/@align | table/@pgwide" mode="xslLib:cals2html.attributes"/> <xsl:template match="table/@orient | table/@tabstyle | table/@shortentry | table/@tocentry | tgroup/@tgroupstyle | entry/@rotate" mode="xslLib:cals2html.attributes" priority="1"> <!--FIXME : rotate could be done with css3--> <xsl:choose> <xsl:when test="$xslLib:cals2html.html-version = 5"> <xsl:attribute name="data-cals-{local-name(.)}" select="."/> </xsl:when> <xsl:otherwise> <xsl:next-match/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="tgroup/@char | tgroup/@charoff | entry/@char | entry/@charoff" mode="xslLib:cals2html.attributes"> <xsl:if test="$xslLib:cals2html.html-version le 4"> <xsl:copy-of select="."/> </xsl:if> </xsl:template> <!--Attributes to keep as is--> <xsl:template match="@xml:* | @id" mode="xslLib:cals2html.attributes"> <xsl:copy copy-namespaces="no"/> </xsl:template> <xsl:template match="@*" mode="xslLib:cals2html.attributes"> <xsl:choose> <xsl:when test="$xslLib:cals2html-keep-unmatched-attributes"> <xsl:attribute name="{concat($xslLib:cals2html-unmatched-attributes-prefix, local-name(.))}" select="."/> </xsl:when> <xsl:otherwise> <xsl:message>[ERROR] <xsl:value-of select="name(parent::*)"/>/@<xsl:value-of select="name()"/> unmatched in mode "xslLib:cals2html.attributes"</xsl:message> </xsl:otherwise> </xsl:choose> </xsl:template> <!--copy template--> <xsl:template match="node() | @*" mode="xslLib:cals2html.main"> <xsl:copy copy-namespaces="no"> <xsl:apply-templates select="node() | @*" mode="#current"/> </xsl:copy> </xsl:template> <!--==================================--> <!--COMMON --> <!--==================================--> <!--cf. https://www.oasis-open.org/specs/tm9901.html#AEN530 : @colwidth might be express in different units : - proportinal values like : "5*", "10%" - fixed values like : “pt” (points), “cm” (centimeters), “mm” (millimeters), “pi” (picas), and “in” (inches) => FIXME mricaud : j'ai l'impression qu'ici on ne gère que les proportionnel, faut-il prévoir les fixes ? --> <!--FIXME : here we get the new colwidth as percent ("500*, 500*" would be converted as "50%, 50%") But we should treat differently by unit : - unit : % => let it the same - unit : * => make it % - unit px => let it the same (or make it %) ?--> <!--Add @width or @style="width:..." on current element--> <xsl:template name="xslLib:cals2html.add-column-width"> <xsl:param name="colspec-list-for-total-width" required="yes" as="element(colspec)*"/> <xsl:param name="colspec-list-for-current-width" required="yes" as="element(colspec)*"/> <xsl:variable name="width" as="xs:string"> <xsl:choose> <xsl:when test="count($colspec-list-for-current-width) = 0"> <xsl:text>ignore</xsl:text> </xsl:when> <xsl:when test="xslLib:cals2html.colspecWidthUnitAreTheSame($colspec-list-for-current-width)"> <xsl:variable name="colspec-list-for-current-width.unit" select="$colspec-list-for-current-width[1]/@colwidth/xslLib:cals2html.getWidthUnit(.)" as="xs:string"/> <xsl:choose> <!--current unit is fixed--> <xsl:when test="xslLib:cals2html.unitIsFixed($colspec-list-for-current-width.unit)"> <xsl:value-of select="concat( sum($colspec-list-for-current-width/@colwidth/xslLib:cals2html.getWidthValue(.)), $colspec-list-for-current-width.unit)"/> </xsl:when> <!--current unit is proportional--> <xsl:otherwise> <xsl:choose> <!--unit is "%" : keep it the same (just round it)--> <xsl:when test="$colspec-list-for-current-width.unit = '%'"> <xsl:value-of select="concat( round(sum($colspec-list-for-current-width/@colwidth/xslLib:cals2html.getWidthValue(.))), $colspec-list-for-current-width.unit)"/> </xsl:when> <!--unit is "*" : make it "%" (from the total width)--> <xsl:otherwise> <xsl:choose> <!--total width units are consistent--> <xsl:when test="xslLib:cals2html.colspecWidthUnitAreTheSame($colspec-list-for-total-width)"> <xsl:variable name="colspec-list-for-total-width.unit" select="$colspec-list-for-total-width[1]/@colwidth/xslLib:cals2html.getWidthUnit(.)" as="xs:string"/> <xsl:choose> <!--total width units are consistent with current cell units--> <xsl:when test="$colspec-list-for-current-width.unit = $colspec-list-for-total-width.unit"> <xsl:variable name="total-colwidth-sum" select="sum($colspec-list-for-total-width/@colwidth/xslLib:cals2html.getWidthValue(.))" as="xs:double"/> <xsl:variable name="current-colwidth-sum" select="sum($colspec-list-for-current-width/@colwidth/xslLib:cals2html.getWidthValue(.))" as="xs:double"/> <xsl:sequence select="concat( round($current-colwidth-sum div $total-colwidth-sum * 100), '%')"/> </xsl:when> <xsl:otherwise> <xsl:message terminate="no">[ERROR][cals2html.xsl] total width units are NOT consistent with current cell units at <xsl:sequence select="els:get-xpath($colspec-list-for-current-width[1])"/></xsl:message> <xsl:text>error</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:when> <!--total width units are not consistent--> <xsl:otherwise> <xsl:message terminate="no">[ERROR][cals2html.xsl] total width units are not consistent at <xsl:sequence select="els:get-xpath($colspec-list-for-current-width[1])"/></xsl:message> <xsl:text>error</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:when> <!--unconsitent units for the current cells--> <xsl:otherwise> <xsl:message terminate="no">[ERROR][cals2html.xsl] unconsitent units for the current cells at <xsl:sequence select="els:get-xpath($colspec-list-for-current-width[1])"/></xsl:message> <xsl:text>error</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:choose> <xsl:when test="$width = ('ignore', 'error')"> <!--no width--> </xsl:when> <xsl:when test="string(xslLib:cals2html.getWidthValue($width)) = ''"> <xsl:message>[ERROR][cals2html.xsl] Unable to compute width (empty) at <xsl:value-of select="els:get-xpath(.)"/> : <xsl:value-of select="els:displayNode(.)"/></xsl:message> </xsl:when> <xsl:when test="string(xslLib:cals2html.getWidthValue($width)) = 'NaN'"> <xsl:message>[ERROR][cals2html.xsl] Unable to compute width (<xsl:value-of select="$width"/>) at <xsl:value-of select="els:get-xpath(.)"/> : <xsl:value-of select="els:displayNode(.)"/></xsl:message> </xsl:when> <xsl:when test="string(xslLib:cals2html.getWidthValue($width)) = '0'"> <xsl:message>[WARNING][cals2html.xsl] width=<xsl:value-of select="$width"/> will not be computed</xsl:message> </xsl:when> <xsl:when test="$xslLib:cals2html.compute-column-width-as-width-attribute"> <xsl:attribute name="style" select="concat('width:', $width)"/> </xsl:when> <xsl:otherwise> <xsl:attribute name="width" select="$width"/> </xsl:otherwise> </xsl:choose> </xsl:template> <!--From a width with its unit (like 10px), get the unit (px)--> <xsl:function name="xslLib:cals2html.getWidthUnit" as="xs:string"> <xsl:param name="width" as="xs:string"/> <xsl:sequence select="replace($width, '\d|\.', '')"/> </xsl:function> <!--Check if a unit is a proportional one--> <xsl:function name="xslLib:cals2html.unitIsProportional" as="xs:boolean"> <xsl:param name="unit" as="xs:string"/> <xsl:sequence select="$unit = ('%', '*')"/> </xsl:function> <!--check if a unit is fixed (not a proportional one)--> <xsl:function name="xslLib:cals2html.unitIsFixed" as="xs:boolean"> <xsl:param name="unit" as="xs:string"/> <xsl:sequence select="not(xslLib:cals2html.unitIsProportional($unit))"/> </xsl:function> <!--From a width with its unit (like 10px), get the value (10)--> <xsl:function name="xslLib:cals2html.getWidthValue" as="xs:double"> <xsl:param name="width" as="xs:string"/> <xsl:variable name="value.string" select="substring-before($width, xslLib:cals2html.getWidthUnit($width))" as="xs:string"/> <xsl:choose> <xsl:when test="$value.string castable as xs:double"> <xsl:sequence select="number($value.string)"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="xs:double('NaN')"/> </xsl:otherwise> </xsl:choose> </xsl:function> <!--Check if every units of a colspec list are consistent (the same)--> <xsl:function name="xslLib:cals2html.colspecWidthUnitAreTheSame" as="xs:boolean"> <xsl:param name="colspec-list" as="element(colspec)*"/> <xsl:variable name="colspec-1.unit" select="$colspec-list[@colwidth][1]/@colwidth/xslLib:cals2html.getWidthUnit(.)" as="xs:string?"/> <xsl:choose> <xsl:when test="count($colspec-list) = 0 or count($colspec-1.unit) = 0"> <xsl:sequence select="false()"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="every $unit in $colspec-list/@colwidth/xslLib:cals2html.getWidthUnit(.) satisfies $unit = $colspec-1.unit"/> </xsl:otherwise> </xsl:choose> </xsl:function> <!--Get the @colnum of a colspec. If the attribute doesn't exist, the function will return the position of the colspec amongs the other colspec--> <xsl:function name="xslLib:cals2html.get-colnum" as="xs:integer"> <xsl:param name="entry" as="element(entry)?"/> <!--only for debug--> <xsl:param name="colspec" as="element(colspec)?"/> <xsl:choose> <xsl:when test="exists($colspec)"> <xsl:sequence select="($colspec/@colnum[normalize-space(.) != ''], count($colspec/preceding-sibling::colspec) + 1)[1]"/> </xsl:when> <xsl:otherwise> <xsl:message terminate="yes">[ERROR][cals2html.xsl] Calling xslLib:cals2html.get-colnum() with $colspec empty argument <xsl:sequence select="els:get-xpath($entry)"/></xsl:message> <xsl:sequence select="0"/> </xsl:otherwise> </xsl:choose> </xsl:function> <!--==============================================================================================================================--> <!-- STEP 3 : class2style --> <!--==============================================================================================================================--> <xsl:variable name="xslLib:cals2html.class2style.mapping" as="element()"> <!--Using cals namespace here so we can match elements with the xpath default namespace--> <mapping xmlns="http://docs.oasis-open.org/ns/oasis-exchange/table"> <!-- frame ne se trouve qu'au niveau de l'élément table --> <entry key="cals_frame-top">border-top:1px solid</entry> <entry key="cals_frame-bottom">border-bottom:1px solid</entry> <entry key="cals_frame-topbot">border-top:1px solid; border-bottom:1px solid</entry> <entry key="cals_frame-sides">border-left:1px solid; border-right:1px solid</entry> <entry key="cals_frame-all">border:1px solid</entry> <entry key="cals_frame-none">border:none</entry> <!-- align --> <entry key="cals_align-left">text-align:left</entry> <entry key="cals_align-right">text-align:right</entry> <entry key="cals_align-center">text-align:center</entry> <entry key="cals_align-justify">text-align:justify</entry> <!-- FIXME sera utile pour les tableaux issus de FrameMaker <entry key="cals_alignchar">text-align:left</entry> --> <!-- valign --> <entry key="cals_valign-top">vertical-align:top</entry> <entry key="cals_valign-bottom">vertical-align:bottom</entry> <entry key="cals_valign-middle">vertical-align:middle</entry> <!-- colsep --> <entry key="cals_colsep">border-right:1px solid</entry> <!-- rowsep --> <entry key="cals_rowsep">border-bottom:1px solid</entry> </mapping> </xsl:variable> <xsl:template match="html:table[els:hasClass(., 'cals_tgroup')] | html:table[els:hasClass(., 'cals_tgroup')]//*[local-name(.) = ('tr', 'td', 'th', 'thead', 'tbody', 'tfoot')]" mode="xslLib:cals2html.class2style"> <xsl:copy> <xsl:copy-of select="@* except (@class | @style)"/> <xsl:variable name="class" select="tokenize(@class, '\s+')[not(. = $xslLib:cals2html.class2style.mapping/entry/@key)]" as="xs:string*"/> <xsl:if test="not(empty($class))"> <xsl:attribute name="class" select="string-join($class, ' ')"/> </xsl:if> <xsl:variable name="style" as="xs:string*"> <xsl:sequence select="tokenize(@style, ';')"/> <xsl:for-each select="tokenize(@class, '\s+')[. = $xslLib:cals2html.class2style.mapping/entry/@key]"> <xsl:variable name="val" select="." as="xs:string"/> <xsl:sequence select="tokenize($xslLib:cals2html.class2style.mapping/entry[@key = $val], ';')"/> </xsl:for-each> </xsl:variable> <xsl:if test="not(empty($style))"> <xsl:attribute name="style" select="string-join($style, '; ')"/> </xsl:if> <xsl:copy-of select="@* except (@class | @style)"/> <xsl:apply-templates mode="#current"/> </xsl:copy> </xsl:template> <!--Default copy--> <xsl:template match="* | @* | node()" mode="xslLib:cals2html.class2style"> <xsl:copy> <xsl:apply-templates select="@* | node()" mode="#current"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xslLib="http://www.lefebvre-sarrut.eu/ns/els/xslLib" version="3.0" exclude-result-prefixes="#all"> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>Set xml:base attribute on the top level element of the document</xd:p> <xd:p>This is usefull when initiating a multi-step xslt (with variables containing each step), calling base-uri() in any step will then work fine</xd:p> <xd:p>See : https://www.oxygenxml.com/archives/xsl-list/200601/msg00687.html</xd:p> </xd:desc> </xd:doc> <xsl:param name="xslLib:baseUri" select="base-uri()" as="xs:anyURI"/> <!--==============================================================================================================================--> <!-- INIT --> <!--==============================================================================================================================--> <xsl:template match="/"> <xsl:apply-templates select="/" mode="xslLib:setXmlBase"/> </xsl:template> <!--==============================================================================================================================--> <!-- MAIN --> <!--==============================================================================================================================--> <xsl:template match="/*" mode="xslLib:setXmlBase"> <xsl:copy> <xsl:attribute name="xml:base" select="$xslLib:baseUri"/> <xsl:apply-templates select="@* | node()" mode="#current"/> </xsl:copy> </xsl:template> <!--copy template--> <xsl:template match="* | @* | node()" mode="xslLib:setXmlBase"> <xsl:copy> <xsl:apply-templates select="@* | node()" mode="#current"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xslLib="http://www.lefebvre-sarrut.eu/ns/els/xslLib" version="3.0" exclude-result-prefixes="#all"> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>Remove xml:base attribute on the top level element of the document</xd:p> <xd:p>This XSLT in the reverse of setXmlBase.xsl. It is usefull for XSPEC testing of multi-step XSLT where the xml:base is usefull during processing but should be delete at the end so xspec does't complain.</xd:p> </xd:desc> </xd:doc> <!--==============================================================================================================================--> <!-- INIT --> <!--==============================================================================================================================--> <xsl:template match="/"> <xsl:apply-templates select="/" mode="xslLib:removeXmlBase"/> </xsl:template> <!--==============================================================================================================================--> <!-- MAIN --> <!--==============================================================================================================================--> <xsl:template match="/*" mode="xslLib:removeXmlBase"> <xsl:copy> <xsl:apply-templates select="@* except @xml:base | node()" mode="#current"/> </xsl:copy> </xsl:template> <!--copy template--> <xsl:template match="* | @* | node()" mode="xslLib:removeXmlBase"> <xsl:copy> <xsl:apply-templates select="@* | node()" mode="#current"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:els="http://www.lefebvre-sarrut.eu/ns/els" xmlns:xslLib="http://www.lefebvre-sarrut.eu/ns/els/xslLib" xmlns:cals="http://docs.oasis-open.org/ns/oasis-exchange/table" xmlns="http://docs.oasis-open.org/ns/oasis-exchange/table" version="3.0" xpath-default-namespace="http://docs.oasis-open.org/ns/oasis-exchange/table" exclude-result-prefixes="#all"> <!--<xsl:import href="els-common.xsl"/>--> <xd:doc scope="stylesheet"> <xd:desc> <xd:p>Normalize Cals Table</xd:p> </xd:desc> </xd:doc> <!--==============================================================================================================================--> <!-- INIT --> <!--==============================================================================================================================--> <xsl:template match="/"> <xsl:apply-templates select="/" mode="xslLib:normalizeCalsTable"/> </xsl:template> <!--==============================================================================================================================--> <!-- MAIN --> <!--==============================================================================================================================--> <!--Normalize yesorno values (0/false or 1/true becomes yes/no)--> <xsl:template match=" table/@colsep | table/@rowsep | table/@tocentry | table/@shortentry | table/@pgwide | tgroup/@colsep | tgroup/@rowsep | colspec/@colsep | colspec/@rowsep | spanspec/@colsep | spanspec/@rowsep | row/@rowsep | entrytbl/@colsep | entrytbl/@rowsep | entry/@colsep | entry/@rowsep | entry/@rotate" mode="xslLib:normalizeCalsTable"> <xsl:choose> <xsl:when test=". = ('0', '1')"> <xsl:next-match/> </xsl:when> <xsl:when test=". = ('yes', 'no')"> <xsl:attribute name="{name(.)}" select="if(. = 'yes') then ('1') else('0')"/> </xsl:when> <xsl:otherwise> <xsl:message>[ERROR][normalizeCalsTable.xsl] attribute <xsl:value-of select="name()"/>="<xsl:value-of select="."/>" should be a boolean value, it has been ignored </xsl:message> </xsl:otherwise> </xsl:choose> </xsl:template> <!--add empty colwidth if none exist--> <xsl:template match="colspec[not(@colwidth)]" mode="xslLib:normalizeCalsTable"> <xsl:copy copy-namespaces="no"> <xsl:apply-templates select="@*" mode="#current"/> <xsl:attribute name="colwidth"/> <xsl:apply-templates select="node()" mode="#current"/> </xsl:copy> </xsl:template> <!--Normalize @colwidth value--> <xsl:template match="colspec/@colwidth" mode="xslLib:normalizeCalsTable"> <!--lowercase and no spaces--> <xsl:variable name="value.normalized" select="replace(lower-case(.), '\s', '')" as="xs:string"/> <!--adding unit "*" if none--> <xsl:attribute name="colwidth"> <xsl:choose> <!--no unit--> <xsl:when test="replace(., '(\d|\.)', '') = ''"> <xsl:value-of select="concat($value.normalized, '*')"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$value.normalized"/> </xsl:otherwise> </xsl:choose> </xsl:attribute> </xsl:template> <!--copy template--> <xsl:template match="* | @* | node()" mode="xslLib:normalizeCalsTable"> <xsl:copy> <xsl:apply-templates select="@* | node()" mode="#current"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:html="http://www.w3.org/1999/xhtml" exclude-result-prefixes="xs html" version="3.0"> <xsl:template name="importJsElTable"> <script xmlns="http://www.w3.org/1999/xhtml" src="https://code.jquery.com/jquery-3.2.1.min.js"/> <script xmlns="http://www.w3.org/1999/xhtml"> <xsl:attribute name="type" select="'text/javascript'"/> <xsl:text disable-output-escaping="yes"> try { $(function(){ $(document).ready(function() { $('.Tet1niv').parent().addClass('Tet1niv') $('.Tet2niv').parent().addClass('Tet2niv') $('.Tet3niv').parent().addClass('Tet3niv') $('.Tetverticale').parent().addClass('Tetverticale') }); }); } catch(err) {} </xsl:text> </script> </xsl:template> <xsl:template match="html:body" mode="injectJS"> <body xmlns="http://www.w3.org/1999/xhtml"> <xsl:for-each select="@*"> <xsl:copy-of select="."/> </xsl:for-each> <xsl:call-template name="importJsElTable"/> <xsl:apply-templates mode="#current"/> </body> </xsl:template> <xsl:template match="@* | node()" mode="injectJS"> <xsl:copy> <xsl:apply-templates select="@* | node()" mode="injectJS"/> </xsl:copy> </xsl:template> </xsl:stylesheet>