2012-06-27 5 views
5

EDIT - ho capito la soluzione al mio problema e postato un Q & A here.escludere alcuni nodi figlio quando la struttura dei dati è sconosciuta

Sto cercando di elaborare XML conforme allo standard EAD Library of Congress (trovato here). Sfortunatamente, lo standard è molto lento per quanto riguarda la struttura dell'XML.

Ad esempio il tag <bioghist> può esistere all'interno del tag <archdesc>, o all'interno di un tag <descgrp>, o inserito all'interno di un altro <bioghist> tag, o una combinazione di quanto sopra, oppure può essere lasciata completamente. Ho trovato molto difficile selezionare solo il tag biogisto che sto cercando senza selezionarne anche altri.

seguito sono riportati alcuni documenti diversi possibili EAD XML mia XSLT potrebbe avere a processo:

Primo esempio

<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> 

Secondo esempio

<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> 

Terzo esempio

Come si può vedere, un file XML EAD potrebbe avere un tag <bioghist> quasi ovunque. L'output effettivo che suppongo di produrre è troppo complicato per postare qui. Un esempio semplificato di uscita per le tre EAD esempi potrebbe essere come:

uscita per Primo esempio

<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> 

uscita per Secondo esempio

<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> 

uscita per il terzo esempio

<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> 

Se voglio estrarre il "primo" valore del biografo e inserirlo nello <primary_record>, non posso semplicemente <xsl:apply-templates select="/ead/eadheader/archdesc/bioghist", poiché tale tag potrebbe non essere un diretto discendente del tag <archdesc>. Potrebbe essere racchiuso tra <descgrp> o <bioghist> o una combinazione di questi. E non posso select="//bioghist", perché quello tirerà tutti i i tag <bioghist>. Non riesco nemmeno a select="//bioghist[1]" perché potrebbe non esserci effettivamente un tag <bioghist> e quindi inserirò il valore sotto lo <c01>, che è "Secondo" e dovrebbe essere elaborato in seguito.

Questo è già un post lungo, ma un'altra ruga è che può esistere un numero illimitato di nodi <cxx>, nidificati fino a dodici livelli di profondità. Attualmente sto elaborandoli ricorsivamente. Ho provato a salvare il nodo che sto attualmente elaborando (<c01> per esempio) come variabile chiamata 'RN', quindi in esecuzione <xsl:apply-templates select=".//bioghist [name(..)=name($RN) or name(../..)=name($RN)]">.Questo funziona per alcune forme di EAD, in cui il tag <bioghist> non è nidificato troppo profondamente, ma non funzionerà se dovrà elaborare un file EAD creato da qualcuno che ama il wrapping dei tag in altri tag (che è completamente soddisfacente secondo il EAD Standard).

Quello che mi piacerebbe è in qualche modo di dire

  • ottenere qualsiasi <bioghist> tag ovunque sotto il nodo corrente, ma
  • non scavare più a fondo se si colpisce un <c??> tag

I spero di aver chiarito la situazione. Per favore fatemi sapere se ho lasciato qualcosa di ambiguo. Qualsiasi assistenza che puoi fornire sarebbe molto apprezzata. Grazie.

risposta

0

Ho elaborato una soluzione da sola e l'ho pubblicata in questo Q&A perché la soluzione è piuttosto specifica per un determinato standard XML e sembrava fuori dallo scopo di questa domanda. Se le persone sentono che sarebbe meglio pubblicarlo anche qui, posso aggiornare questa risposta con una copia.

2

Poiché i requisiti sono piuttosto vaghi, qualsiasi risposta riflette solo le ipotesi che il suo autore ha fatto.

Qui è mio:

<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> 

Quando questa trasformazione viene applicata sul documento XML fornito:

<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> 

il risultato voluto è prodotto:

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

Mi scuso per il fatto che i requisiti sono vaghi. Un documento EAD xml appropriato contiene 30 o 40 informazioni diverse, ciascuna con il proprio tag. L'output che sto generando fa uso di tutti quei tag diversi e ho pensato che un input/output semplificato potrebbe essere il modo migliore per trasmettere la natura del problema. Il tuo xslt è un po 'più avanzato di quello che conosco, ma penso di aver capito alcuni pezzi. Il modello che corrisponde al biologo verrà eseguito solo tre volte, ogni volta creando un elemento con un nome diverso, corretto? Ora la mia domanda è: perché il modello esegue solo 3 volte. – aarondev

+0

@aarondev: la risposta è semplice: ci sono solo tre elementi nel documento XML fornito che corrispondono al modello. Il modello corrisponde a qualsiasi 'biografo' nel documento XML, il cui primo nodo fratello successivo è un elemento' descgrp' - ci sono esattamente tre di tali elementi 'bioghist' nel documento XML fornito. –

+0

Quindi i seguenti fratelli corrispondono a tutti i nodi fratelli. E quindi stai selezionando solo il primo di quei fratelli con il [1], giusto? Il bit di self :: descgrp mi ha ancora confuso. Questo sta rendendo il nodo corrente il nodo descgrp? – aarondev

Problemi correlati