Pregunta

Tengo algunos XML, por ejemplo, se parece a esto:

<root>
    <field1>test</field1>
    <f2>t2</f2>
    <f2>t3</f2>
</root>

Quiero transformarlo con XSLT, pero quiero suprimir el segundo elemento f2 en la salida. ¿Cómo verifico dentro de mi plantilla para ver si el elemento f2 ya existe en la salida cuando el segundo elemento f2 en la fuente? ¿es procesado? Mi XSLT se ve algo como esto en este momento:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="no" omit-xml-declaration="yes" standalone="no" />
  <xsl:template match="/">
    <xsl:for-each select="./root">
      <output>
        <xsl:apply-templates />        
      </output>
    </xsl:for-each>
  </xsl:template>
  <xsl:template match="*" >
      <xsl:element name="{name(.)}">
        <xsl:value-of select="." />
      </xsl:element>
  </xsl:template>
</xsl:stylesheet>

Necesito hacer algún tipo de comprobación alrededor del elemento xsl: en la plantilla, creo, pero no estoy seguro de cómo interrogar el documento de salida para ver si el elemento ya está presente.

Editar: olvidó las etiquetas previas, ¡el código debería estar visible ahora!

¿Fue útil?

Solución

Depende de lo ancho del sistema que quieras ser.

es decir, ¿Le preocupan solo los elementos que son hijos del mismo padre o todos los elementos del mismo nivel ("primos" si lo desea) o elementos en cualquier parte del documento ...

En la primera situación, puedes verificar el eje de hermanos anteriores para ver si existe algún otro elemento con el mismo nombre.

<xsl:if test="count(preceding-sibling::node()[name()=name(current())])=0">
  ... do stuff in here.
</xsl:if>

Otros consejos

Para solo verificar (y advertirle de un duplicado), puede encontrar un ejemplo aquí

Algo a lo largo de las líneas de:

<xsl:for-each-group select="collection(...)//@id" group-by=".">
  <xsl:if test="count(current-group()) ne 1">
    <xsl:message>Id value <xsl:value-of select="current-grouping-key()"/> is 
       duplicated in files
       <xsl:value-of select="current-group()/document-uri(/)" separator=" and
    "/></xsl:message>
  </xsl:if>
 </xsl:for-each-group>

Se modificará para seleccionar todos los nodos dentro del elemento 'raíz'.

Para eliminar las líneas duplicadas, tiene otro ejemplo aquí

Eso se vería así:

<xsl:stylesheet>
  <xsl:key name="xyz" match="record[x/y/z]" use="x/y/z" />
  <xsl:variable name="noxyzdups" select="/path/to/record[generate-id(.) = generate-id(key('xyz', x/y/z))]" />
...
  <xsl:template ... >
    <xsl:copy-of "exslt:node-set($noxyzdups)" />
  </xsl:template>
</xsl:stylesheet>

x / y / z es la expresión xpath que desea que sea única. Puede ser concat (x, '-', @ y, '-', z) o lo que quieras.

Ahora no estoy seguro de que esos dos ejemplos puedan adaptarse fácilmente a su caso, pero solo quería señalar esas dos fuentes, en caso de que sea de utilidad.

No es posible interrogar la salida de su transformación. Tampoco es posible rastrear el estado actual de su transformación (es decir, hacer un seguimiento de los nodos que ha emitido en una variable). Fundamentalmente, no es así como funciona XSLT. Uno de los costos de un entorno de programación sin efectos secundarios es que no puede hacer cosas que tengan efectos secundarios. Oh bien.

En su caso, una forma de lograr esto sería construir una variable que contuviera una lista de todos los elementos de origen que podrían transformarse en el elemento de salida que desea emitir solo una vez. Luego, verifica cada nodo que estás transformando en esta lista. Si no está en la lista, emítelo. Si es el primer elemento de la lista, emítelo. De lo contrario, no.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top