Avatar billede jesperwerge Nybegynder
28. oktober 2008 - 15:18 Der er 18 kommentarer og
1 løsning

gruppering af 2 elementer på samme level

Hej Eksperter,

Jeg har en XMl struktur der ser således ud:
<Root>
<Adress>
<felter...>
</Adress>
<Reading>
<felter....>
</Reading>
<Reading>
<felter....>
</Reading>
<Adress>
<felter...>
</Adress>
<Reading>
<felter....>
</Reading>
<Reading>
<felter....>
</Reading>
<Reading>
<felter....>
</Reading>
<Reading>
<felter....>
</Reading>
<Adress>
<felter...>
</Adress>
<Reading>
<felter....>
</Reading>
<Reading>
<felter....>
</Reading>
<Adress>
<felter...>
</Adress>
<Reading>
<felter....>
</Reading>
<Reading>
<felter....>
</Reading>
<Reading>
<felter....>
</Reading>
<Reading>
<felter....>
</Reading>
</Root>

I xml filen kommer X antal Adress tags og tilførende X antal Reading under hver Adress, De kommer i den rigtige rækkefølge.
jeg har et xsl hvor jeg gerne vil vise det som det står i xml filen, men når jeg bruger  2 x "for-each" kommer alle reading under hver adress.

Kan man ikke få det således at adress for kun de Readings der findes før den næste Adress kommer osv.?

/Werge
Avatar billede aaberg Nybegynder
28. oktober 2008 - 15:20 #1
I din anden for-each, skal du have et punktum forand x-pathen "./reading". Så søger den kun undernoder, og ikke i hele dokumentet.
Avatar billede jesperwerge Nybegynder
28. oktober 2008 - 15:21 #2
Jeg vil gerne beholde den struktur der er i xml filen, men ved ikke hvordan når der er kommer flere af samme elementer som ikke er grupperet sammen.
<Root>

<Adress>
<felter...>
</Adress>
<Reading>
<felter....>
</Reading>
<Reading>
<felter....>
</Reading>

<Adress>
<felter...>
</Adress>
<Reading>
<felter....>
</Reading>
<Reading>
<felter....>
</Reading>
<Reading>
<felter....>
</Reading>
<Reading>
<felter....>
</Reading>

<Adress>
<felter...>
</Adress>
<Reading>
<felter....>
</Reading>
<Reading>
<felter....>
</Reading>

<Adress>
<felter...>
</Adress>
<Reading>
<felter....>
</Reading>
<Reading>
<felter....>
</Reading>
<Reading>
<felter....>
</Reading>
<Reading>
<felter....>
</Reading>

</Root>
Avatar billede softspot Forsker
28. oktober 2008 - 15:22 #3
Hvordan ser din XSL ud (prøv at paste den ind i tråden her)?
Avatar billede aaberg Nybegynder
28. oktober 2008 - 15:33 #4
Jeg havde ikke lige opdaget at det var en flad struktur.

En af reglerne omkring xml er, at rækkefølgen af noderne ikke skal betyde noget. Så det du har gang i, modstrider xml specifikationen. Og jeg tror ikke det kan lade sig gøre at tage højde for det i en x-path.
Avatar billede jesperwerge Nybegynder
28. oktober 2008 - 15:47 #5
første del af håndtering af Adress ser således ud:
<xsl:template>
  <xsl:for-each select="Adress">
    <tr>
      <td>
        <b>adresse</b>
        <br/>
        <xsl:value-of select="AddressID"/>
        <br/>
        <xsl:value-of select="Street"/>
        <br/>
        <xsl:value-of select="District"/>
        <xsl:text>  </xsl:text>
        <xsl:value-of select="CityName"/>
        <br/>
        <br/>
      </td>
    </tr>
    <xsl:apply-templates select="Reading"/>
  </xsl:for-each>
</xsl:template>

Templaten for Reading ser således ud:

  <xsl:template match="Reading">
  <tr>
      <td colspan="3" style="border-bottom: gainsboro thin solid;">
        <font face="Arial" size="2">
          <b>Måler nr. </b>
          <xsl:value-of select="MeterNumber"/>
          <b> Faktor:  </b>
          <xsl:value-of select="MeterConstant"/>
          <br/>
        </font>
      </td>
    </tr>
    <tr valign="Top">
      <td>
        <font face="Arial" size="2">
          <b>Dato for aflæsning</b>
        </font>
      </td>
      <td>
        <font face="Arial" size="2">
          <b>Måler er aflæst til  (kWh))</b>
        </font>
      </td>
      <td>
        <font face="Arial" size="2">
          <b>Dit forbrug i kWh</b>
        </font>
      </td>
    </tr>
    <!-- Start på Meter spec som en liste -->
    <xsl:for-each select="Reading">
      <tr valign="Top">
        <td>
          <xsl:value-of select="ReadingDate"/>
        </td>
        <td>
          <xsl:value-of select="PreviousStand"/>
        </td>
        <td style="border-bottom: gainsboro thin solid;"></td>
      </tr>
      <tr valign="Top">
        <td style="border-bottom: gainsboro thin solid;">
          <xsl:value-of select="ReadingDate"/>
        </td>
        <td style="border-bottom: gainsboro thin solid;">
          <xsl:value-of select="Stand"/>
        </td>
        <td style="border-bottom: gainsboro thin solid;">
          <xsl:value-of select="Quantity"/>
        </td>
      </tr>
      <tr>
        <td height="10px" column="3"></td>
      </tr>
    </xsl:for-each>

    <tr valign="Top">
      <td valign="Top" colspan="3" style="border-bottom: gainsboro thin solid;">
        <br/>
        <xsl:value-of select="Comments"/>
        <br/>
      </td>
    </tr>
</xsl:template>
Avatar billede jokkejensen Novice
28. oktober 2008 - 16:02 #6
Du skal bruge <xsl:call-template> med parametre, sæt en bool alt efter hvad næste nodes name() er.

Kald den så recursivt fra samme template.
Avatar billede jokkejensen Novice
28. oktober 2008 - 16:04 #7
Og væk med den xsl:for-each, det er bad practice ! - Brug apply-template.
Avatar billede jesperwerge Nybegynder
28. oktober 2008 - 16:11 #8
jokkejensen: det lyder ret fornemt det du skriver, men jeg er ikke så god til dette endnu, kunne du give et kort eksempel?
Avatar billede jokkejensen Novice
28. oktober 2008 - 16:16 #9
yeah, men skal det fungere, vil jeg gerne have noget test xml, hvis du har noget uden person data..

Ellers kan jeg gætte 1000 gange :)
Avatar billede jokkejensen Novice
28. oktober 2008 - 16:18 #10
men ellers bare noget ala:

following-sibling::node()/name() = 'Adress' Spring ud, eller count(following-sibling::Adress) Når den bliver en mindre, spring ud.
Avatar billede jesperwerge Nybegynder
28. oktober 2008 - 16:31 #11
yeah, det kan du tro jeg har :)

<?xml version="1.0" encoding="utf-8"?>
<Root>
  <Adress>
    <AddressID>1a3ee569</AddressID>
    <Street>malsoparken 1</Street>
    <District>Frederiksberg</District>
    <CityName>kbh</CityName>
  </Adress>
  <Reading>
      <PreviousReadingDate>10102008</PreviousReadingDate>
      <PreviousStand>10</PreviousStand>
      <PreviousQuantity>1</PreviousQuantity>
  </Reading>
    <Reading>
      <PreviousReadingDate>10102008</PreviousReadingDate>
      <PreviousStand>10</PreviousStand>
      <PreviousQuantity>1</PreviousQuantity>
  </Reading>
  <Adress>
      <AddressID>1a3ee579</AddressID>
      <Street>malsoparken 10</Street>
      <District>Frederiksberg</District>
      <CityName>kbh</CityName>
  </Adress>
    <Reading>
      <PreviousReadingDate>10102008</PreviousReadingDate>
      <PreviousStand>10</PreviousStand>
      <PreviousQuantity>1</PreviousQuantity>
  </Reading>
    <Reading>
      <PreviousReadingDate>10102008</PreviousReadingDate>
      <PreviousStand>10</PreviousStand>
      <PreviousQuantity>1</PreviousQuantity>
    </Reading>
    <Reading>
      <PreviousReadingDate>10102008</PreviousReadingDate>
      <PreviousStand>10</PreviousStand>
      <PreviousQuantity>1</PreviousQuantity>
  </Reading>
    <Reading>
      <PreviousReadingDate>10102008</PreviousReadingDate>
      <PreviousStand>10</PreviousStand>
      <PreviousQuantity>1</PreviousQuantity>
  </Reading>
    <Adress>
      <AddressID>1a3ee492</AddressID>
      <Street>malsoparken 5</Street>
      <District>Frederiksberg</District>
      <CityName>kbh</CityName>
  </Adress>
    <Reading>
      <PreviousReadingDate>10102008</PreviousReadingDate>
      <PreviousStand>10</PreviousStand>
      <PreviousQuantity>1</PreviousQuantity>
    </Reading>
    <Reading>
      <PreviousReadingDate>10102008</PreviousReadingDate>
      <PreviousStand>10</PreviousStand>
      <PreviousQuantity>1</PreviousQuantity>
  </Reading>
</Root>

og tilhørende xsl:

<xsl:template>
  <xsl:for-each select="Adress">
    <tr>
      <td>
        <b>adresse</b>
        <br/>
        <xsl:value-of select="AddressID"/>
        <br/>
        <xsl:value-of select="Street"/>
        <br/>
        <xsl:value-of select="District"/>
        <xsl:text>  </xsl:text>
        <xsl:value-of select="CityName"/>
        <br/>
        <br/>
      </td>
    </tr>
    <xsl:apply-templates select="Reading"/>
  </xsl:for-each>
</xsl:template>
  Templaten for Reading ser således ud:

  <xsl:template match="Reading">
  <tr>
      <td colspan="3" style="border-bottom: gainsboro thin solid;">
        <font face="Arial" size="2">
          <b>Måler nr. </b>
          <!-- <xsl:value-of select="MeterNumber"/> -->
          <b> Faktor:  </b>
          <!-- <xsl:value-of select="MeterConstant"/> -->
          <br/>
        </font>
      </td>
    </tr>
    <tr valign="Top">
      <td>
        <font face="Arial" size="2">
          <b>Dato for aflæsning</b>
        </font>
      </td>
      <td>
        <font face="Arial" size="2">
          <b>Måler er aflæst til  (kWh))</b>
        </font>
      </td>
      <td>
        <font face="Arial" size="2">
          <b>Dit forbrug i kWh</b>
        </font>
      </td>
    </tr>
    <!-- Start på Meter spec som en liste -->
    <xsl:for-each select="Reading">
      <tr valign="Top">
        <td>
          <xsl:value-of select="PreviousReadingDate"/>
        </td>
        <td>
          <xsl:value-of select="PreviousStand"/>
        </td>
        <td style="border-bottom: gainsboro thin solid;"></td>
      </tr>
      <tr valign="Top">
        <td style="border-bottom: gainsboro thin solid;">
          <xsl:value-of select="ReadingDate"/>
        </td>
        <td style="border-bottom: gainsboro thin solid;">
          <xsl:value-of select="Stand"/>
        </td>
        <td style="border-bottom: gainsboro thin solid;">
          <xsl:value-of select="Quantity"/>
        </td>
      </tr>
      <tr>
        <td height="10px" column="3"></td>
      </tr>
    </xsl:for-each>

    <tr valign="Top">
      <td valign="Top" colspan="3" style="border-bottom: gainsboro thin solid;">
        <br/>
        <xsl:value-of select="Comments"/>
        <br/>
      </td>
    </tr>
</xsl:template>
</xsl:stylesheet>
Avatar billede jokkejensen Novice
28. oktober 2008 - 16:43 #12
<template match="/">   
<xsl:variable name="MessyXml">
      <Root>
        <Adress>
          <AddressID>1a3ee569</AddressID>
          <Street>malsoparken 1</Street>
          <District>Frederiksberg</District>
          <CityName>kbh</CityName>
        </Adress>
        <Reading>
          <PreviousReadingDate>10102008</PreviousReadingDate>
          <PreviousStand>10</PreviousStand>
          <PreviousQuantity>1</PreviousQuantity>
        </Reading>
        <Reading>
          <PreviousReadingDate>10102008</PreviousReadingDate>
          <PreviousStand>10</PreviousStand>
          <PreviousQuantity>1</PreviousQuantity>
        </Reading>
        <Adress>
          <AddressID>1a3ee579</AddressID>
          <Street>malsoparken 10</Street>
          <District>Frederiksberg</District>
          <CityName>kbh</CityName>
        </Adress>
        <Reading>
          <PreviousReadingDate>10102008</PreviousReadingDate>
          <PreviousStand>10</PreviousStand>
          <PreviousQuantity>1</PreviousQuantity>
        </Reading>
        <Reading>
          <PreviousReadingDate>10102008</PreviousReadingDate>
          <PreviousStand>10</PreviousStand>
          <PreviousQuantity>1</PreviousQuantity>
        </Reading>
        <Reading>
          <PreviousReadingDate>10102008</PreviousReadingDate>
          <PreviousStand>10</PreviousStand>
          <PreviousQuantity>1</PreviousQuantity>
        </Reading>
        <Reading>
          <PreviousReadingDate>10102008</PreviousReadingDate>
          <PreviousStand>10</PreviousStand>
          <PreviousQuantity>1</PreviousQuantity>
        </Reading>
        <Adress>
          <AddressID>1a3ee492</AddressID>
          <Street>malsoparken 5</Street>
          <District>Frederiksberg</District>
          <CityName>kbh</CityName>
        </Adress>
        <Reading>
          <PreviousReadingDate>10102008</PreviousReadingDate>
          <PreviousStand>10</PreviousStand>
          <PreviousQuantity>1</PreviousQuantity>
        </Reading>
        <Reading>
          <PreviousReadingDate>10102008</PreviousReadingDate>
          <PreviousStand>10</PreviousStand>
          <PreviousQuantity>1</PreviousQuantity>
        </Reading>
      </Root>
    </xsl:variable>
    <xsl:apply-templates select="msxml:node-set($MessyXml)//Adress"></xsl:apply-templates>
  </xsl:template>

  <xsl:template match="Adress">
    <h1>
      <xsl:value-of select="AddressID"/>
    </h1>
    <xsl:apply-templates select="./following-sibling::Reading"></xsl:apply-templates>               
  </xsl:template>

  <xsl:template match="Reading">
    Reading
  </xsl:template>


Så du skal vel bare erstatte : <xsl:apply-templates select="Reading"/> med <xsl:apply-templates select="following-sibling::Reading"/>
Avatar billede jokkejensen Novice
28. oktober 2008 - 16:44 #13
hov nej, never mind... der skal den parameter med :)
Avatar billede jesperwerge Nybegynder
28. oktober 2008 - 17:01 #14
jokkejensen: Jeg vender stærk tilbage senere på aftenen eller i morgen. jeg kigger på dit forslag - hvor vil du have parameter med når du ikke bruger call-template?

eller misforstår jeg det helt?

Werge
Avatar billede jokkejensen Novice
28. oktober 2008 - 18:37 #15
nej jeg tog helt fejl, skulle lige have noget fodder.

aaberg havde vist rimeligt ret i at det er smartest at gruppere xmlen fra start af ordentligt, at transportere resten af kilden rundt med <xsl:call-template> så ryger der lidt performance.

Men følende kode grupperer det, så kan du let selv style det:

<xsl:template match="/">
    <!-- Copy paste af dit xml -->
    <xsl:variable name="MessyXml">
      <Root>
        <Adress>
          <AddressID>1a3ee569</AddressID>
          <Street>malsoparken 1</Street>
          <District>Frederiksberg</District>
          <CityName>kbh</CityName>
        </Adress>
        <Reading>
          <PreviousReadingDate>10102008</PreviousReadingDate>
          <PreviousStand>10</PreviousStand>
          <PreviousQuantity>1</PreviousQuantity>
        </Reading>
        <Reading>
          <PreviousReadingDate>10102008</PreviousReadingDate>
          <PreviousStand>10</PreviousStand>
          <PreviousQuantity>1</PreviousQuantity>
        </Reading>
        <Adress>
          <AddressID>1a3ee579</AddressID>
          <Street>malsoparken 10</Street>
          <District>Frederiksberg</District>
          <CityName>kbh</CityName>
        </Adress>
        <Reading>
          <PreviousReadingDate>10102008</PreviousReadingDate>
          <PreviousStand>10</PreviousStand>
          <PreviousQuantity>1</PreviousQuantity>
        </Reading>
        <Reading>
          <PreviousReadingDate>10102008</PreviousReadingDate>
          <PreviousStand>10</PreviousStand>
          <PreviousQuantity>1</PreviousQuantity>
        </Reading>
        <Reading>
          <PreviousReadingDate>10102008</PreviousReadingDate>
          <PreviousStand>10</PreviousStand>
          <PreviousQuantity>1</PreviousQuantity>
        </Reading>
        <Reading>
          <PreviousReadingDate>10102008</PreviousReadingDate>
          <PreviousStand>10</PreviousStand>
          <PreviousQuantity>1</PreviousQuantity>
        </Reading>
        <Adress>
          <AddressID>1a3ee492</AddressID>
          <Street>malsoparken 5</Street>
          <District>Frederiksberg</District>
          <CityName>kbh</CityName>
        </Adress>
        <Reading>
          <PreviousReadingDate>10102008</PreviousReadingDate>
          <PreviousStand>10</PreviousStand>
          <PreviousQuantity>1</PreviousQuantity>
        </Reading>
        <Reading>
          <PreviousReadingDate>10102008</PreviousReadingDate>
          <PreviousStand>10</PreviousStand>
          <PreviousQuantity>1</PreviousQuantity>
        </Reading>
      </Root>
    </xsl:variable>
    <!-- Transformere det om til grupper -->
    <xsl:variable name="NiceXml" xml:space="default">
      <xsl:apply-templates select="msxml:node-set($MessyXml)" mode="cleanXml"></xsl:apply-templates>
    </xsl:variable>
    <!-- Udskriver det til test -->
    <textarea>
      <xsl:copy-of select="$NiceXml"></xsl:copy-of>
    </textarea>
  </xsl:template>

<!-- Template der rydder det op -->
  <xsl:template match="*" mode="cleanXml" xml:space="default">
    <Root>
      <xsl:for-each select="*">
        <xsl:choose>
          <xsl:when test="name()='Adress'">
            <xsl:text disable-output-escaping="yes"><![CDATA[<Group>]]></xsl:text>
            <xsl:copy-of select="."/>
          </xsl:when>
          <xsl:when test="name()='Reading'">
            <xsl:if test="name(following-sibling::*) = 'Adress'">
              <xsl:copy-of select="."/>
              <xsl:text disable-output-escaping="yes"><![CDATA[</Group>]]></xsl:text>
            </xsl:if>
            <xsl:if test="name(following-sibling::*) != 'Adress'">
              <xsl:copy-of select="."/>
            </xsl:if>
          </xsl:when>
        </xsl:choose>
      </xsl:for-each>
      <xsl:text disable-output-escaping="yes"><![CDATA[</Group>]]></xsl:text>
    </Root>
  </xsl:template>



Output =

<Root>
  <Group>
    <Adress>
      <AddressID>1a3ee569</AddressID>
      <Street>malsoparken 1</Street>
      <District>Frederiksberg</District>
      <CityName>kbh</CityName>
    </Adress>
    <Reading>
      <PreviousReadingDate>10102008</PreviousReadingDate>
      <PreviousStand>10</PreviousStand>
      <PreviousQuantity>1</PreviousQuantity>
    </Reading>
    <Reading>
      <PreviousReadingDate>10102008</PreviousReadingDate>
      <PreviousStand>10</PreviousStand>
      <PreviousQuantity>1</PreviousQuantity>
    </Reading>
  </Group>
  <Group>
    <Adress>
      <AddressID>1a3ee579</AddressID>
      <Street>malsoparken 10</Street>
      <District>Frederiksberg</District>
      <CityName>kbh</CityName>
    </Adress>
    <Reading>
      <PreviousReadingDate>10102008</PreviousReadingDate>
      <PreviousStand>10</PreviousStand>
      <PreviousQuantity>1</PreviousQuantity>
    </Reading>
    <Reading>
      <PreviousReadingDate>10102008</PreviousReadingDate>
      <PreviousStand>10</PreviousStand>
      <PreviousQuantity>1</PreviousQuantity>
    </Reading>
    <Reading>
      <PreviousReadingDate>10102008</PreviousReadingDate>
      <PreviousStand>10</PreviousStand>
      <PreviousQuantity>1</PreviousQuantity>
    </Reading>
    <Reading>
      <PreviousReadingDate>10102008</PreviousReadingDate>
      <PreviousStand>10</PreviousStand>
      <PreviousQuantity>1</PreviousQuantity>
    </Reading>
  </Group>
  <Group>
    <Adress>
      <AddressID>1a3ee492</AddressID>
      <Street>malsoparken 5</Street>
      <District>Frederiksberg</District>
      <CityName>kbh</CityName>
    </Adress>
    <Reading>
      <PreviousReadingDate>10102008</PreviousReadingDate>
      <PreviousStand>10</PreviousStand>
      <PreviousQuantity>1</PreviousQuantity>
    </Reading>
    <Reading>
      <PreviousReadingDate>10102008</PreviousReadingDate>
      <PreviousStand>10</PreviousStand>
      <PreviousQuantity>1</PreviousQuantity>
    </Reading>
  </Group>
</Root>


Så kan du bare zappe igennem med <xsl:apply-templates>

Vh.
Avatar billede jesperwerge Nybegynder
28. oktober 2008 - 20:37 #16
jokkejensen: det ser sku da cool ud det der, det må jeg kigge nærmere på i morgen. jeg vender stærkt tilbage.

:)

/Werge
Avatar billede jesperwerge Nybegynder
04. november 2008 - 08:04 #17
hej jokkejensen,

Det ser ud til at virke - :)

jeg har ikke fået testet det igennem endnu, men jeg er helt klar med på hvad du vil opnå.

smid et svar så får du points.

PS: undskyld den lange vente tid :(

/Werge
Avatar billede jokkejensen Novice
04. november 2008 - 14:12 #18
Yeah, bemærk lige at det godt kan være den nye variable med noderne, den jeg udskriver i <textarea> nok skal behandles med msxml:node-set(), der tager en tekst streng og laver om til et node sæt. Så kan du arbede videre med det.

Husk at inkludere xml namespace msxml i dit <stylesheet> ala: xmlns:msxml="urn:schemas-microsoft-com:xslt" og evt fjerne prefixet gennem exclude-prefixes="msxml"..

Ellers siger du bare til, jeg er ikke lige så go til at vende tilbage, så opret en ny.
Avatar billede jesperwerge Nybegynder
07. november 2008 - 09:59 #19
Hey jokkejensen - tak for yderligere info - jeg opretter en ny hvis det bliver nødvendigt :)
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
Kategori
Kurser inden for grundlæggende programmering

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