J'ai une exigence où j'aimerais avoir une instruction if else pour vérifier si un nœud a des attributs ou s'il a juste une chaîne.
Par exemple: 1 du nœud a 0 File(s) found
et l'autre a des attributs tels que <autoincludesystem_info mdate='08/23/2011' mtime='09:51' ampm='PM' filesize='64' filename='AFP_p.tgp' />
Voici un échantillon de deux nœuds
<product>
<autoIncludeUser>0 File(s) found</autoIncludeUser>
<autoIncludeSystem>
<autoincludesystem_info mdate='08/23/2011' mtime='09:51' ampm='PM' filesize='64' filename='AFP_p.tgp' />
<autoincludesystem_info mdate='08/23/2011' mtime='09:51' ampm='PM' filesize='3,879' filename='AnalystsExpressionMacros.tgp' />
<autoincludesystem_info mdate='08/23/2011' mtime='09:51' ampm='PM' filesize='475' filename='base64Converter.tgp' />
<autoincludesystem_info mdate='08/23/2011' mtime='09:51' ampm='PM' filesize='<DIR>' filename='codePages' />
</autoIncludeSystem>
<autoIncludeStudio>0 File(s) found</autoIncludeStudio>
<externalLibrarySystem>
<externalLibrarySystem_info mdate='08/23/2011' mtime='09:52' ampm='PM' filesize='196,608' filename='AFPtoXML_DP.dll' />
<externalLibrarySystem_info mdate='08/23/2011' mtime='09:52' ampm='PM' filesize='13,259' filename='ASN1toXSDRunner.jar' />
<externalLibrarySystem>
</product>
Comment pourrais-je identifier si un nœud n'a que des chaînes ou des attributs et sur cette base, je peux obtenir les valeurs String
ou attrib values
respectivement.
Vous pouvez remplacer l'ensemble de votre xsl:choose
instruction avec:
<xsl:apply-templates select="autoIncludeSystem"/>
puis ajoutez deux modèles:
<xsl:template match="autoIncludeSystem[autoincludesystem_info/@*]>
<!-- code for elements with attributes (xsl:when) -->
</xsl:template>
<xsl:template match="autoIncludeSystem[not(autoincludesystem_info/@*)]>
<!-- code for elements without attributes (xsl:otherwise) -->
</xsl:template>
Nous pouvons le faire autrement en utilisant le code ci-dessous
<xsl:choose>
<xsl:when test="something to test">
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
Voici donc ce que j'ai fait
<h3>System</h3>
<xsl:choose>
<xsl:when test="autoIncludeSystem/autoincludesystem_info/@mdate"> <!-- if attribute exists-->
<p>
<dd><table border="1">
<tbody>
<tr>
<th>File Name</th>
<th>File Size</th>
<th>Date</th>
<th>Time</th>
<th>AM/PM</th>
</tr>
<xsl:for-each select="autoIncludeSystem/autoincludesystem_info">
<tr>
<td valign="top" ><xsl:value-of select="@filename"/></td>
<td valign="top" ><xsl:value-of select="@filesize"/></td>
<td valign="top" ><xsl:value-of select="@mdate"/></td>
<td valign="top" ><xsl:value-of select="@mtime"/></td>
<td valign="top" ><xsl:value-of select="@ampm"/></td>
</tr>
</xsl:for-each>
</tbody>
</table>
</dd>
</p>
</xsl:when>
<xsl:otherwise> <!-- if attribute does not exists -->
<dd><pre>
<xsl:value-of select="autoIncludeSystem"/><br/>
</pre></dd> <br/>
</xsl:otherwise>
</xsl:choose>
Ma sortie
solution I. Xpath 1.0 - utilisez cette seule expression XPath:
concat(substring('String', 1 div boolean(text())),
' ',
substring('attrib values', 1 div boolean(@*))
)
Voici une vérification basée sur XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="*[not(*)]">
<xsl:value-of select="concat(' ', name(),': ')"/>
<xsl:value-of select=
"concat(substring('String', 1 div boolean(text())),
' ',
substring('attrib values', 1 div boolean(@*))
)
"/>
</xsl:template>
</xsl:stylesheet>
lorsque cette transformation est appliquée sur le document XML fourni (légèrement corrigé pour être bien formé):
<product>
<autoIncludeUser>0 File(s) found</autoIncludeUser>
<autoIncludeSystem>
<autoincludesystem_info mdate='08/23/2011' mtime='09:51' ampm='PM' filesize='64' filename='AFP_p.tgp' />
<autoincludesystem_info mdate='08/23/2011' mtime='09:51' ampm='PM' filesize='3,879' filename='AnalystsExpressionMacros.tgp' />
<autoincludesystem_info mdate='08/23/2011' mtime='09:51' ampm='PM' filesize='475' filename='base64Converter.tgp' />
<autoincludesystem_info mdate='08/23/2011' mtime='09:51' ampm='PM' filesize='<DIR>' filename='codePages' />
</autoIncludeSystem>
<autoIncludeStudio>0 File(s) found</autoIncludeStudio>
<externalLibrarySystem>
<externalLibrarySystem_info mdate='08/23/2011' mtime='09:52' ampm='PM' filesize='196,608' filename='AFPtoXML_DP.dll' />
<externalLibrarySystem_info mdate='08/23/2011' mtime='09:52' ampm='PM' filesize='13,259' filename='ASN1toXSDRunner.jar' />
</externalLibrarySystem>
</product>
le résultat voulu et correct est produit:
autoIncludeUser: String
autoincludesystem_info: attrib values
autoincludesystem_info: attrib values
autoincludesystem_info: attrib values
autoincludesystem_info: attrib values
autoIncludeStudio: String
externalLibrarySystem_info: attrib values
externalLibrarySystem_info: attrib values
Explication Nous utilisons ces faits:
Pour toute chaîne $s
, substring($s, Infinity)
est la chaîne vide.
1 div 0
Est Infinity
Par définition number(true())
est 1
Et number(false())
est 0.
II. Solution XPath 2.:
C'est beaucoup plus facile dans XPath 2.0 car le langage a un opérateur if/then/else
Standard.
tiliser:
if(text())
then 'String'
else if(@*)
then 'attrib values'
else ()
vérification XSLT 2.0:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="*[not(*)]">
<xsl:value-of select="concat(' ', name(),': ')"/>
<xsl:value-of select=
"if(text())
then 'String'
else if(@*)
then 'attrib values'
else ()
"/>
</xsl:template>
</xsl:stylesheet>
lorsque cette transformation est appliquée sur le même document XML (ci-dessus), encore une fois le résultat voulu et correct est produit:
autoIncludeUser: String
autoincludesystem_info: attrib values
autoincludesystem_info: attrib values
autoincludesystem_info: attrib values
autoincludesystem_info: attrib values
autoIncludeStudio: String
externalLibrarySystem_info: attrib values
externalLibrarySystem_info: attrib values
XPath //*[not(@*)]
sélectionnera tous les éléments qui n'ont pas d'attributs.
Vous pouvez le faire assez facilement en utilisant xsl:choose
- mais très souvent en XSLT, la meilleure façon de faire un traitement conditionnel est d'écrire différentes règles de modèle pour gérer les différentes conditions. Donc, écrivez une règle de modèle avec match="*[@*]"
Pour faire correspondre les éléments qui ont des attributs, et une autre avec match="*[text()]"
pour faire correspondre les éléments qui ont un contenu textuel.