2012-06-27 14 views
5

EDITAR - He descubierto la solución a mi problema y publicado una Q & Un here.excluir ciertos nodos secundarios cuando la estructura de datos es desconocida

Estoy tratando de procesar XML conforme al estándar EAD de la Biblioteca del Congreso (encontrado here). Desafortunadamente, el estándar es muy flexible con respecto a la estructura del XML.

Por ejemplo la etiqueta <bioghist> puede existir dentro de la etiqueta <archdesc>, o dentro de una etiqueta <descgrp>, o anidada dentro de otra <bioghist> etiqueta, o una combinación de lo anterior, o se puede dejar fuera completamente. Descubrí que es muy difícil seleccionar solo la etiqueta biogística que estoy buscando sin seleccionar otras.

A continuación se presentan algunos documentos EAD XML posibles diferentes mi XSLT podría tener a proceso:

Primer ejemplo

<ead> 
<eadheader> 
    <archdesc> 
     <bioghist>one</bioghist> 
     <dsc> 
      <c01> 
       <descgrp> 
        <bioghist>two</bioghist> 
       </descgrp> 
       <c02> 
        <descgrp> 
         <bioghist> 
          <bioghist>three</bioghist> 
         </bioghist> 
        </descgrp> 
       </c02> 
      </c01> 
     </dsc> 
    </archdesc> 
</eadheader> 
</ead> 

Segundo ejemplo

<ead> 
<eadheader> 
    <archdesc> 
     <descgrp> 
      <bioghist> 
       <bioghist>one</bioghist> 
      </bioghist> 
     </descgrp> 
     <dsc> 
      <c01> 
       <c02> 
        <descgrp> 
         <bioghist>three</bioghist> 
        </descgrp> 
       </c02> 
       <bioghist>two</bioghist> 
      </c01> 
     </dsc> 
    </archdesc> 
</eadheader> 
</ead> 

Tercer ejemplo

<ead> 
<eadheader> 
    <archdesc> 
     <descgrp> 
      <bioghist>one</bioghist> 
     </descgrp> 
     <dsc> 
      <c01> 
       <c02> 
        <bioghist>three</bioghist> 
       </c02> 
      </c01> 
     </dsc> 
    </archdesc> 
</eadheader> 
</ead> 

Como puede ver, un archivo EAD XML puede tener una etiqueta <bioghist> en casi cualquier lugar. La salida real que se supone que debo producir es demasiado complicada para publicarla aquí. Un ejemplo simplificado de la salida de los anteriores tres EAD ejemplos podría ser como:

de salida para el primer ejemplo

<records> 
<primary_record> 
    <biography_history>first</biography_history> 
</primary_record> 
<child_record> 
    <biography_history>second</biography_history> 
</child_record> 
<granchild_record> 
    <biography_history>third</biography_history> 
</granchild_record> 
</records> 

de salida para el segundo ejemplo

<records> 
<primary_record> 
    <biography_history>first</biography_history> 
</primary_record> 
<child_record> 
    <biography_history>second</biography_history> 
</child_record> 
<granchild_record> 
    <biography_history>third</biography_history> 
</granchild_record> 
</records> 

salida de Tercera ejemplo

<records> 
<primary_record> 
    <biography_history>first</biography_history> 
</primary_record> 
<child_record> 
    <biography_history></biography_history> 
</child_record> 
<granchild_record> 
    <biography_history>third</biography_history> 
</granchild_record> 
</records> 

Si quiero obtener el "primer" valor biológico y ponerlo en el <primary_record>, no puedo simplemente <xsl:apply-templates select="/ead/eadheader/archdesc/bioghist", ya que esa etiqueta podría no ser un descendiente directo de la etiqueta <archdesc>. Puede estar envuelto por un <descgrp> o un <bioghist> o una combinación de los mismos. Y no puedo select="//bioghist", porque eso sacará todos las etiquetas <bioghist>. No puedo ni siquiera select="//bioghist[1]" porque en realidad podría no haber una etiqueta <bioghist> allí y luego voy a tirar del valor por debajo del <c01>, que es "Segundo" y debería procesarse más tarde.

Esto ya es una publicación larga, pero otra arruga es que puede haber un número ilimitado de nodos <cxx>, anidados hasta doce niveles de profundidad. Actualmente estoy procesándolos recursivamente. Intenté guardar el nodo que estoy procesando actualmente (<c01> por ejemplo) como una variable llamada 'RN', y luego ejecuto <xsl:apply-templates select=".//bioghist [name(..)=name($RN) or name(../..)=name($RN)]">.Esto funciona para algunas formas de EAD, donde la etiqueta <bioghist> no está anidada demasiado profundamente, pero fallará si alguna vez tiene que procesar un archivo EAD creado por alguien que ama envolver etiquetas en otras etiquetas (lo cual es totalmente correcto de acuerdo con el EAD Standard).

Lo que me gusta es de alguna manera de decir

  • obtener ninguna etiqueta <bioghist> en cualquier lugar por debajo del nodo actual, pero
  • No cavar más profundo si se golpea una etiqueta <c??>

I Espero haber aclarado la situación. Por favor, avíseme si he dejado algo ambiguo. Cualquier ayuda que pueda proporcionar sería muy apreciada. Gracias.

Respuesta

0

Inventé una solución por mi cuenta y la publiqué en este Q&A porque la solución es bastante específica para un determinado estándar XML y parecía estar fuera del alcance de esta pregunta. Si las personas sienten que sería mejor publicarlo aquí también, puedo actualizar esta respuesta con una copia.

2

Como los requisitos son bastante vagos, cualquier respuesta solo refleja las conjeturas que ha hecho su autor.

Aquí es mío:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:my="my:my" exclude-result-prefixes="my"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<my:names> 
    <n>primary_record</n> 
    <n>child_record</n> 
    <n>grandchild_record</n> 
</my:names> 

<xsl:variable name="vNames" select="document('')/*/my:names/*"/> 

<xsl:template match="/"> 
    <xsl:apply-templates select= 
    "//bioghist[following-sibling::node()[1] 
           [self::descgrp] 
       ]"/> 
</xsl:template> 

<xsl:template match="bioghist"> 
    <xsl:variable name="vPos" select="position()"/> 

    <xsl:element name="{$vNames[position() = $vPos]}"> 
    <xsl:value-of select="."/> 
    </xsl:element> 
</xsl:template> 

<xsl:template match="text()"/> 
</xsl:stylesheet> 

Cuando se aplica esta transformación en el documento XML proporcionado:

<ead> 
    <eadheader> 
     <archdesc> 
      <bioghist>first</bioghist> 
      <descgrp> 
       <bioghist>first</bioghist> 
       <bioghist> 
        <bioghist>first</bioghist></bioghist> 
      </descgrp> 
      <dsc> 
       <c01> 
        <bioghist>second</bioghist> 
        <descgrp> 
         <bioghist>second</bioghist> 
         <bioghist> 
          <bioghist>second</bioghist></bioghist> 
        </descgrp> 
        <c02> 
         <bioghist>third</bioghist> 
         <descgrp> 
          <bioghist>third</bioghist> 
          <bioghist> 
           <bioghist>third</bioghist></bioghist> 
         </descgrp> 
        </c02> 
       </c01> 
      </dsc> 
     </archdesc> 
    </eadheader> 
</ead> 

el resultado deseado se produce:

<primary_record>first</primary_record> 
<child_record>second</child_record> 
<grandchild_record>third</grandchild_record> 
+0

Me disculpo porque los requisitos sean vagos. Un documento EAD xml adecuado contiene 30 o 40 piezas de información diferentes, cada una con su propia etiqueta. La salida que estoy generando hace uso de todas esas etiquetas, y pensé que una entrada/salida simplificada podría ser la mejor para transmitir la naturaleza del problema. Tu xslt es un poco más avanzado de lo que estoy familiarizado, pero creo que he descubierto algunas piezas. La plantilla que coincide con bioghist solo se ejecutará tres veces, cada vez que se crea un elemento con un nombre diferente, ¿correcto? Ahora mi pregunta es por qué la plantilla solo se ejecuta 3 veces. – aarondev

+0

@aarondev: La respuesta es simple: solo hay tres elementos en el documento XML proporcionado que coinciden con la plantilla. La plantilla coincide con cualquier 'biografía 'en el documento XML, cuyo primer nodo hermano es un elemento' descgrp'; hay exactamente tres de esos elementos 'bioghist' en el documento XML provisto. –

+0

Así que los siguientes hermanos coinciden con todos los nodos hermanos. Y luego seleccionas solo el primero de esos hermanos con el [1], ¿verdad? El bit self :: descgrp todavía me tiene confundido. ¿Eso está convirtiendo al nodo actual en el nodo descgrp? – aarondev

Cuestiones relacionadas