2017-09-05 2 views
0

J'ai un fichier XML où je recherche plusieurs clés qui sont ensuite utilisées pour rechercher plus d'éléments. exemples simplifiés: Vérifiez la personne alimentaire aime puis ajouter les ingrédients pour chacun d'eux comme « liste d'achats »XSLT récupère des valeurs de plusieurs clés?

<?xml version="1.0" encoding="UTF-8"?> 
<foodieparadise> 
    <people> 
    <person name="Frank"> 
     <food>Cake</food> 
     <food>Ice Cream</food> 
     <food>Schnitzel</food> 
    </person> 
     <person name="Joe"> 
      <food>Steak</food> 
      <food>Soup</food> 
      <food>Schnitzel</food> 
      <food>Ice Cream</food> 
     </person> 
    </people> 

    <ingredients> 
     <food name="Ice Cream"> 
      <ingredient>Ice</ingredient> 
      <ingredient>Cream</ingredient> 
     </food> 
     <food name="Cake"> 
      <ingredient>Egg</ingredient> 
      <ingredient>Flour</ingredient> 
      <ingredient>Butter</ingredient> 
      <ingredient>Cream</ingredient> 
     </food> 
     <food name="Schnitzel"> 
      <ingredient>Pork</ingredient> 
      <ingredient>Bread Crumbs</ingredient> 
     </food> 
     <food name="Steak"> 
      <ingredient>Beef</ingredient> 
     </food> 
     <food name="Soup"> 
      <ingredient>Tomato</ingredient> 
      <ingredient>Onions</ingredient> 
      <ingredient>Parsley</ingredient> 
      <ingredient>Egg</ingredient> 
     </food> 
    </ingredients> 
</foodieparadise> 

J'utilise cette XSLT:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    exclude-result-prefixes="xs" 
    version="2.0"> 

    <xsl:output method="text" encoding="UTF-8" /> 

    <xsl:template match="/"> 
     <xsl:apply-templates select="/foodieparadise/people/person" /> 
    </xsl:template> 

    <xsl:template match="person"> 
     <xsl:value-of select="@name"/> likes <xsl:value-of select="count(food)"/> types of food 
and needs to buy <xsl:value-of select="count(distinct-values(/foodieparadise/ingredients/food/ingredient))"/> different ingredients. 

    </xsl:template> 

</xsl:stylesheet> 

Le count(distinct-values(/foodieparadise/ingredients/food/ingredient)) manque l'expression de requête pour la nourriture que chaque personne mange. Donc, je reçois le résultat:

Frank likes 3 types of food and needs to buy 11 different ingredients.   
Joe likes 4 types of food and needs to buy 11 different ingredients. 

mais ce que je dois réaliser est:

Frank likes 3 types of food and needs to buy 7 different ingredients.   
Joe likes 4 types of food and needs to buy 8 different ingredients. 

J'ai essayé count(distinct-values(/foodieparadise/ingredients/food/ingredient[text() = ./food])) mais cela ne retourne rien.

De quoi mon XPath et/ou mon gabarit auraient-ils besoin?

Répondre

1

Vous pouvez également mettre en place une

clé
<xsl:key name="ref" match="ingredients/food" use="@name"/> 

puis l'utiliser

<xsl:template match="person"> 
    <xsl:value-of select="@name"/> likes <xsl:value-of select="count(food)"/> types of food 
    and needs to buy <xsl:value-of select="count(distinct-values(key('ref', food)/ingredient))"/> different ingredients. 

</xsl:template> 
2

Qu'est-ce que vous avez besoin est:

count(distinct-values(/foodieparadise/ingredients/food[@name = current()/food]/ingredient)) 
+0

donc 'string()' est le secret de make XSLT compare les ensembles de valeurs. Allez comprendre. THX! – stwissel

+0

La chaîne '(@name)' est ici redondante (peut être simplifiée en '@ name'), car les opérandes de' = 'sont automatiquement atomisés, et nous pouvons supposer que la valeur de chaîne de l'attribut est presque la même que la valeur typée. Le 'food/string()' me semble incorrect: je soupçonne que 'food/string (@name)' était prévu, auquel cas l'appel sur 'string()' est à nouveau redondant. –

+0

@MichaelKay Thx pour l'écriture, grand fan de votre travail. Juste essayé 'count (distinct-values ​​(/ foodieparadise/ingredients/food [@name = current()/food]/ingrédient))' comme suggéré et cela fonctionne. Intéressant! '@ name' renvoie une chaîne tandis que' current()/food' renvoie un ensemble de chaînes. Donc l'opérateur '=' fonctionne comme (un fictif) 'ismember (string, set)' - Où puis-je en apprendre plus à ce sujet. – stwissel