regulares - transformar xml a xslt
XSLT: ¿Cómo encontrar el recuento de hijos únicos de un nodo? (2)
Si todos los niños
baz
son iguales, entoncesdoSomething
más.doSomething
más. Mi nodo actual esfoo
.
Esto es confuso porque:
-
baz
no son hijos defoo
; - su título dice " encuentre el recuento de niños únicos ", pero no es necesario encontrarlo para saber si son iguales.
Pruebe algo como:
<xsl:template match="foo">
<xsl:variable name="first-baz" select="(bar/baz)[1]" />
<xsl:choose>
<xsl:when test="bar/baz[date!=$first-baz/date or time!=$first-baz/time]">
<!-- THEY ARE NOT ALL SAME -->
</xsl:when>
<xsl:otherwise>
<!-- THEY ARE ALL SAME -->
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Tenga en cuenta que esto supone que cada baz
tiene una date
y una time
. De lo contrario, debe probar not(date=$first-baz/date)
etc.
Ver también: http://www.jenitennison.com/xslt/grouping/muenchian.html
Adicional:
Ahora, suponiendo que todos los elementos
bar/baz
tienen las mismas etiquetas (no necesariamente ladate
y latime
sino que dicena
,b
yc
), ¿cuál sería el atributo de prueba para ese caso?
Esto lo hace significativamente más complejo. Aún así puedes construir una clave:
<xsl:key name="first-baz" match="foo/bar[1]/baz[1]/*" use="name()" />
entonces haz tu prueba:
<xsl:when test="bar/baz/*[. != key(''first-baz'', name())]">
Esto devuelve verdadero si existe cualquier hijo de baz
cuyo valor de cadena sea diferente de un nodo igualmente nombrado que sea hijo del primer baz
.
Tenga en cuenta que la clave, tal como se define aquí, es para todo el documento. Si desea restringir la prueba al antecesor foo
actual, debe incluir su identificación en la clave.
Mi XML se ve así:
<foo>
<bar name="a">
<baz name="xyz">
<time>2</time>
<date>3</date>
</baz>
</bar>
<bar name="b">
<baz name="xyz">
<time>2</time>
<date>3</date>
</baz>
</bar>
<bar name="c">
<baz name="xyz">
<time>2</time>
<date>3</date>
</baz>
</bar>
</foo>
Estoy escribiendo un XSL que necesita funcionar así: Si todos los niños baz
son iguales, entonces doSomething
más. Mi nodo actual es foo
.
Soy nuevo en XSLT y estoy al tanto de los condicionales en XSL. Se ve algo así a partir de ahora:
<xsl:template match="foo">
<xsl:choose>
<xsl:when test="[My condition]">
doSomething()
</xsl:when>
<xsl:otherwise>
doSomethingElse()
</xsl:otherwise>
</xsl:choose>
</xsl:template>
En el ejemplo actual, debería hacer algo doSomething()
ya que todos los elementos baz
son iguales.
Si descubro la cantidad de elementos baz
únicos, puedo probar si es igual a uno. Si es así, entonces haré algo doSomething()
else doSomethingElse()
¿Cómo debo implementar esto? ¿Cuál debería ser MyCondition
?
PD: Mi versión XSL es 1.0
Si desea hacer esto de forma genérica, entonces realmente está ampliando la capacidad de XSLT 1.0 más allá de sus límites de diseño. Pero puede hacerse.
Escriba una plantilla con nombre llamada deep-equal que tome dos elementos como sus argumentos y devuelva una cadena que contenga el carácter "F" si y solo si no son iguales (para sus propósitos).
Puede verse así:
<xsl:template name="deep-equal">
<xsl:param name="a"/>
<xsl:param name="b"/>
<xsl:choose>
<xsl:when test="local-name(a) != local-name(b)">F</xsl:when>
<xsl:when test="namespace-uri(a) != namespace-uri(b)">F</xsl:when>
<xsl:when test="normalize-space(a) != normalize-space(b)">F</xsl:when>
<xsl:when test="count(a/*) != count(b/*)">F</xsl:when>
<xsl:otherwise>
<xsl:variable name="diffs">
<xsl:for-each select="*">
<xsl:variable name="position" select="position()"/>
<xsl:call-template name="deep-equal">
<xsl:with-param name="a" select="."/>
<xsl:with-param name="b" select="$b/*[$position]"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Aplicar esto a todos los pares relevantes de elementos:
<xsl:variable name="comparison">
<xsl:for-each select="baz[position() >= 2]">
<xsl:call-template name="deep-equal">
<xsl:with-param name="a" select="../baz[1]"/>
<xsl:with-param name="b" select="."/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
Prueba si el resultado contiene una "F":
<xsl:if test="contains($comparison, ''F'')">...</xsl:if>