Avatar billede nute Nybegynder
12. januar 2005 - 13:24 Der er 12 kommentarer og
1 løsning

Finde "immediate prededing sibling" i sorteret nodelist

Jeg har et problem, jeg ikke lige kan finde en løsning på. Problemet udarter sig, fra følgende xml:

<STATES>
    <STATE recno="25">
        <ZIP>
            <ZIPCODE>96951</ZIPCODE>
            <AREACODE>670</AREACODE>
            <COUNTY>ROTA</COUNTY>
        </ZIP>
        <ZIP>
            <ZIPCODE>96950</ZIPCODE>
            <COUNTY>SAIPAN</COUNTY>
        </ZIP>
    </STATE>
    <STATE recno="26">
        <ZIP>
            <ZIPCODE>96970</ZIPCODE>
            <COUNTY>EBEYE</COUNTY>
        </ZIP>
        <ZIP>
            <ZIPCODE>96960</ZIPCODE>
            <COUNTY>MAJURO</COUNTY>
        </ZIP>
        <ZIP>
            <ZIPCODE>96970</ZIPCODE>
            <COUNTY>EBEYE</COUNTY>
        </ZIP>
        <ZIP>
            <ZIPCODE>96960</ZIPCODE>
            <COUNTY>MAJURO</COUNTY>
        </ZIP>
    </STATE>
</STATES>

Jeg har behov for at finde unikke <COUNTY/> noder, og returnere disse. Jeg skal med andre ord, lave en transformation, hvor følgende xml bliver genereret:

<COUNTIES>
    <COUNTY>ROTA</COUNTY>
    <COUNTY>SAIPAN</COUNTY>
    <COUNTY>EBEYE</COUNTY>
    <COUNTY>MAJURO</COUNTY>
</COUNTIES>

Jeg har nu vadet rundt i det, og begynder at løbe tom for idéer ... jeg er bange for at det ikke lige kan lade sig gøre, med mindre man laver en rekursiv funktion - hvor man sorterer på .../ZIP/COUNTY for hver iteration, men denne løsning vil ikke være optimal, da xml'en er på ca 109000 linier :-|

den måde jeg ønsker at gøre det på, er at sortere hele xml'en på COUNTY ... fx:

<xsl:apply-templates select="STATES/STATE/ZIP/COUNTY">
    <xsl:sort order="ascending"/>
</xsl:apply-templates>

hvor jeg nede i min template, gjorde noget ála:

<xsl:variable name="vPrecedingCountyName">
    <xsl:value-of select="parent::*/preceding-sibling::*[1]/child::COUNTY"/>
</xsl:variable>

Det jeg så vil gøre, er at tjekke for om navnet, på dét COUNTY jeg står på, er forskellig fra den forrige i listen, men det er lige denne del jeg er usikker på om kan lade sig gøre, da man arbejder på en sorteret nodelist ... den xsl jeg har nu, ser sådan ud ...

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <xsl:template match="/">
        <xsl:element name="COUNTIES">
            <xsl:apply-templates select="STATES/STATE/ZIP/COUNTY">
                <xsl:sort order="ascending"/>
            </xsl:apply-templates>
        </xsl:element>
    </xsl:template>
    <xsl:template match="COUNTY">
        <xsl:variable name="pStateRecno">
            <xsl:value-of select="parent::*/parent::*/@recno"/>
        </xsl:variable>
        <xsl:variable name="vPrecedingCountyName">
            <xsl:value-of select="parent::*/preceding-sibling::*/child::COUNTY"/>
        </xsl:variable>
        <xsl:choose>
            <xsl:when test="position() = 1">
                <xsl:element name="COUNTY">
                    <xsl:attribute name="state"><xsl:value-of select="$pStateRecno"/></xsl:attribute>
                    <xsl:value-of select="."/>
                </xsl:element>
            </xsl:when>
            <xsl:otherwise>
                <xsl:choose>
                    <xsl:when test=". = $vPrecedingCountyName"/>
                    <xsl:otherwise>
                        <xsl:element name="COUNTY">
                            <xsl:attribute name="state"><xsl:value-of select="$pStateRecno"/></xsl:attribute>
                            <xsl:value-of select="."/>
                        </xsl:element>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

Meeeen ... det fungerer ikke ... any ideas anyone ?

/nute
Avatar billede janegil Nybegynder
12. januar 2005 - 13:54 #1
Det er vel her SQL er greiere enn XML...lage kommaseparert output, importere til Access, og hente ut unike county navn derfra? Men det virker bare hvis counties har unike navn innen staten, og det er utrolig hvor mange steder som heter Austin i Texas.
Avatar billede nute Nybegynder
12. januar 2005 - 14:16 #2
true ... men nu har jeg desværre ikke andet end en xml fil at arbejde med, så den går ikke ;-)

én 'nem' måde, er jo at scripte denne operation, og manipulere xml'en via DOM, men jeg havde håbet på at løse problemeet direkte i min xsl.

/nute
Avatar billede Slettet bruger
12. januar 2005 - 14:21 #3
Hej nute

Måske du kan bruge mit svar på den her til noget: http://eksperten.dk/spm/557234

Ellers skal jeg prøve at lave en custom-løsning til dig...
/CS
Avatar billede janegil Nybegynder
12. januar 2005 - 14:42 #4
har du XML og XSLT, kan du lage deg en kommaseparert output, hvis du ellers kan bruke den til noe
Avatar billede Slettet bruger
12. januar 2005 - 15:09 #5
Her er to templates der kan lave dit ønskede output:

<xsl:template match="/">
  <COUNTIES>
      <xsl:apply-templates select="STATES" />
  </COUNTIES>
</xsl:template>
 
<xsl:template match="STATES">
  <xsl:for-each select="STATE/ZIP/COUNTY">
      <xsl:sort select="." data-type="text" order="ascending" />
      <xsl:if test="count(preceding::COUNTY[. = current()]) = 0">
        <xsl:copy-of select="." />
      </xsl:if>
  </xsl:for-each>
</xsl:template>

/CS
Avatar billede nute Nybegynder
12. januar 2005 - 16:46 #6
coolness ... .jeg vidste det skulle være relativt nemt ;-)

danke sehr !!
Avatar billede Slettet bruger
13. januar 2005 - 00:45 #7
Ja velbekomme da!

(Dog *er* sorterede nodesets ikke de nemmeste at danse med i alle henseender)

/CS
Avatar billede nute Nybegynder
13. januar 2005 - 08:48 #8
yup ... det er jo sant.  den blev lige modificeret lidt, da det var denne linie

<xsl:if test="count(preceding::COUNTY[. = current()]) = 0">

jeg egentlig var på jagt efter.

Som jeg nævnte, var min xml *ret* stor ... der er i alt ca 10000 unikke counties i min xml (totalt 110000 linier), og hvis jeg skal lave en <xsl:sort> i min <xsl:for-each/>, så vil det være en meget tung transformation at udføre. Min xsl ser nu sådan ud:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <xsl:template match="/">
        <xsl:apply-templates/>
    </xsl:template>
    <xsl:template match="STATES">
        <xsl:element name="COUNTIES">
            <xsl:apply-templates select="STATE/ZIP/COUNTY">
                <xsl:sort order="ascending"/>
            </xsl:apply-templates>
        </xsl:element>
    </xsl:template>
    <xsl:template match="COUNTY">
        <xsl:variable name="pStateRecno">
            <xsl:value-of select="parent::*/parent::*/@recno"/>
        </xsl:variable>
        <xsl:if test="count(preceding::COUNTY[. = current()]) = 0">
            <xsl:element name="COUNTY">
                <xsl:attribute name="staterecno"><xsl:value-of select="$pStateRecno"/></xsl:attribute>
                <xsl:value-of select="."/>
            </xsl:element>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

Igen - tak !

/nute
Avatar billede Slettet bruger
13. januar 2005 - 09:09 #9
Hehe - med *den* mængde data må man jo sno sig... just out of curiosity: Hvor meget sparer du ved at droppe sort'en i dette tilfælde? (sekunder, halve/hele minutter?)

/CS
Avatar billede nute Nybegynder
13. januar 2005 - 09:32 #10
hmm ... *meget* mystisk ... en 'uofficiel' test (transformation i XMLSpy og stopur) gav følgende resultat:

MED sort:
3:30
UDEN sort:
3:31

nu kørte jeg flere applikationer på samme tid, når jeg udførte trans uden sort, så det kan godt være at dette har en indvirkning på resultatet, men jeg havde regnet med at der var større forskel ... hmm ...

/nute
Avatar billede Slettet bruger
13. januar 2005 - 09:45 #11
Nu er det vel ikke freeware-udgaven af "stopur" vel? Den skulle være ret fejlbehæftet har jeg læst :-)

Nu kender jeg ikke XMLSpy særlig godt, men har den evt. noget smart cache-stuff som kunne påvirke resultaterne? (Den bruger MSXML's processor, ikke?)

/CS
Avatar billede janegil Nybegynder
13. januar 2005 - 11:14 #12
XMLSpy kan velge mellom MSXML og sin egen, dessuten skal man kunne plugge inn 3.parts prsessorer, men jeg har ikke klart å få Sablotron til å kjøre der.

Uansett, skal man gjøre det til en vane med 3 minutters transformasjoner, kan det være vel verdt å se på http://www.gingerall.cz/charlie/ga/xml/p_sab.xml, den kjører greit og kjapt i en .bat
Avatar billede nute Nybegynder
13. januar 2005 - 11:28 #13
greystate >> det er 'freehand' udgaven af stopur ... "kigge-på-uret-når-trans-starter-og-når-trans-stopper"-versionen ;-) *gaaab*

xmlspy er sat op til MSXML processor. Det gør intet om trans tager 3 minutter, da det er en "en-gang-pr-halvår" operation ... Hvis man havde for vane at transformere denne mængde data, bør man se på leverencen af selve data ...
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester