Expression XSL / XPath pour vérifier si un nœud contient au moins un enfant non vide
Je dois vérifier si un nœud XML a au moins un enfant non vide. Appliqué à ce XML, l'expression doit renvoyer true
<xml>
<node>
<node1/>
<node2/>
<node3>value</node3>
</node>
</xml>
J'ai essayé d'utiliser cette expression: <xsl:if test="not(/xml/node/child::* = '')">
, mais il semble à vérifier si tous les les enfants ne sont pas vides.
Comment puis-je écrire une expression qui retourne true
si , au moins un élément n'est pas vide? Existe-t-il un moyen de le faire sans créer un autre modèle pour itérer sur le noeud chldren?
UPD: je pense à compter non-nœuds vides commetest="count(not(/xml/node/child::* = '')) > '0'"
mais en quelque sorte ne peut pas le faire fonctionner correctement. Cette expression n'est pas bien formée.
4 réponses
Plus précis, plus simple et plus efficace (pas besoin d'utiliser le count()
function):
/*/node/*[text()]
Si vous voulez exclure tout élément qui n'a que des enfants de texte uniquement avec des espaces, Utilisez:
/*/node/*[normalize-space()]
Vous avez juste besoin de <xsl:if test="/xml/node/* != ''" />
.
Dans XPath un =
ou !=
comparaison où un côté est un ensemble de nœuds et de l'autre côté est une chaîne réussit si tout des nœuds dans l'ensemble passe à la comparaison. Ainsi
not(x = '')
Signifie "ce n'est pas le cas qu'un élément enfant x
du nœud courant ait une valeur de chaîne vide", ce qui est fondamentalement différent de
x != ''
Qui signifie "au moins un élément enfant x
du nœud courant a une valeur de chaîne qui n'est pas vide". En particulier, si vous souhaitez vérifier que tous x
les enfants sont vides, vous devez utiliser un "double négatif" test
not(x != '')
Voici un XPath qui devrait accomplir le travail:
count(/*/node/*[text()]) > 0
Lorsqu'il est utilisé dans un exemple XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:value-of select="count(/*/node/*[text()]) > 0" />
</xsl:template>
</xsl:stylesheet>
...qui est, à son tour, appliqué à L'exemple XML fourni:
<xml>
<node>
<node1/>
<node2/>
<node3>value</node3>
</node>
</xml>
...le résultat attendu est produit:
true
Si nous appliquons le même XSLT contre un XML simplement Modifié:
<xml>
<node>
<node1/>
<node2/>
<node3/>
</node>
</xml>
...encore une fois, le résultat attendu est produit:
false
Explication:
Le XPath utilisé recherche tous les enfants d'un élément <node>
(qui sont, à leur tour, des enfants de l'élément racine) qui ont une valeur de texte non vide (comme spécifié par text()
); si le nombre de ces enfants <node>
est supérieur à 0, alors le XPath se résout à true
.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:value-of select="/*/node/*[string-length(text()) >0]!=''"/>
</xsl:template>
</xsl:stylesheet>
Explication Cela trouvera le premier noeud avec une longueur de chaîne supérieure à zéro, puis comparera ce contenu de noeud avec une chaîne vide (la comparaison renverra l'existence d'un noeud de chaîne non vide); ce code peut également être utilisé pour rechercher un critère spécifique dans n'importe quel noeud, par exemple identifier l'existence d'un noeud qui contient une chaîne spécifique ou commence par un caractère ou toute autre condition; veuillez l'utiliser comme condition interne de la référence de noeud pour le code pour travailler sa magie.