Avatar billede tejl Nybegynder
07. maj 2002 - 10:11 Der er 8 kommentarer og
1 løsning

avanceret XSLT - output fra websters ordbog

hej.

Jeg har brug for at processere websters ordbog. Jeg forklarer mit problem med et eksempel.

Filen har strukturen:
<dictionary>

<p><hw>Own</hw> ..... </p>
<p><andet tag>....</andet tag>...</p>
.
.
.
<p><hw>det næste ord</hw>......</p>
.
.
</dictionary>

Alt som hører til ordet "Own" er det p element, som own ligger i , samt de efterfølgende p elementer indtil <p><hw>det næste ord</hw>...</p> nås.

Jeg har brug for at skrive et stylesheet der søger på own og skriver:

<p><hw>Own</hw> ..... </p>
<p><andet tag>....</andet tag>...</p>
.
.
.

dvs alle p elementer der hører til ordet "own", ud i en ny xml fil.

Hvordan gør jeg det?
Avatar billede janegil Nybegynder
08. maj 2002 - 10:12 #1
select="p[preceding::p/hw][position=1][@text='Own']
?
select="p[preceding::p/hw][position=1 and @text='Own']
?
Avatar billede janegil Nybegynder
13. maj 2002 - 23:16 #2
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:param name="find">Own</xsl:param>
    <xsl:template match="dictionary">
        <HTML>
            <HEAD>
                <META http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>
                <TITLE>&quot;<xsl:value-of select="$find"/>&quot; entry from Webster&apos;s</TITLE>
            </HEAD>
            <BODY>
                <H1>&quot;<xsl:value-of select="$find"/>&quot; entry from Webster&apos;s</H1>
                <xsl:apply-templates select="p[./hw=$find]"/>
            </BODY>
        </HTML>
    </xsl:template>
   
    <xsl:template match="p[./hw]">
        <xsl:choose>
            <xsl:when test="./hw=$find">
                <xsl:apply-templates select="following-sibling::p[1]"></xsl:apply-templates>
                <!-- following-sibling::p[1] is in this case the first p for the wanted entry -->
            </xsl:when>
            <xsl:otherwise>
                <!-- Not applying templates, thus stopping processing at the first hw element after the wanted one -->
            </xsl:otherwise>
        </xsl:choose>

  </xsl:template>
 
    <xsl:template match="p">
        <!-- P that is 'content' of a HW 'element' -->
        <!-- Could be any P 'inside' a HW, but template will only be invoked for the 'right' Ps -->
        <xsl:copy-of select="."></xsl:copy-of>
        <xsl:apply-templates select="following-sibling::p[1]"></xsl:apply-templates>
        <!-- following-sibling::p[1] is in this case p's for the wanted entry, from the second to the last -->
    </xsl:template>
</xsl:stylesheet>
Avatar billede janegil Nybegynder
14. maj 2002 - 09:36 #3
xsl:choose er noe av et fremmedelement i XSLT. Jeg tror den blir overflødig, hvis vi bruker

following-sibling::p[1][not(hw)]
Avatar billede janegil Nybegynder
15. maj 2002 - 10:08 #4
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:param name="find">Own</xsl:param>
<xsl:template match="dictionary">
  <HTML>
  <HEAD>
    <TITLE>&quot;<xsl:value-of select="$find"/>&quot; entry from Webster&apos;s</TITLE>
  </HEAD>
  <BODY>
    <H1>&quot;<xsl:value-of select="$find"/>&quot; entry from Webster&apos;s</H1>
    <!-- For each p not containing hw and where the previous hw contains the wanted keyword -->
    <xsl:for-each select="p[not(hw)][preceding-sibling::p[hw][1][hw=$find]]">               
    <xsl:copy-of select="."/>
    </xsl:for-each>
  </BODY>
  </HTML>
</xsl:template>   
</xsl:stylesheet>

Samme perverse glede som å programmere APL eller kompakt C++ :
p[not(hw)][preceding-sibling::p[hw][1][hw=$find]]

Den blir så innviklet fordi det er lite samsvar mellom semantisk og syntaktisk struktur i XML'en: Info om ett ord er en semantisk enhet, det burde syntaktisk medføre at denne informasjonen var samlet i ett element.

Webster er en tykk bok - jeg regner med at det første forslaget mitt kjører raskere.

Stilarket gjør ikke nøyaktig som du ba om, men jeg har fått overbevist meg selv om at jeg kan finne ut av det, så jeg gir meg her.
Avatar billede janegil Nybegynder
15. maj 2002 - 10:13 #5
p[not(hw)][preceding-sibling::p[hw][1][hw=$find]]|p[hw=$find]
for å få med det første p-elementet også?
Avatar billede tejl Nybegynder
15. maj 2002 - 22:58 #6
Hej janegil

Undskyld mit meget sene svar. Mit projekt tog en anden drejning og jeg har først nu haft tid til at vende tilbage til xslt-processeringen. Der er mærkbart forskel på dine 2 løsninger. Den første kører MEGET hurtigere end den anden løsning. Desuden er der en lille fejl i den første løsning. Hvis der er flere definitioner af 'Own' i samme ordbog går det lidt galt. Jeg skulle nok bare have forklaret at et ord kan være defineret flere gange, men med forskellige betydninger. Anyway så har jeg rettet fejlen.
Jeg skulle desuden bruge p elementet indeholdende ordet.
Min endelige løsning er derfor blevet. den følgende:

<?xml version="1.0" encoding="iso-8859-1"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
  xmlns="http://www.w3.org/1999/xhtml" >
  <xsl:output method="xml" encoding="iso-8859-1"
    doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
    doctype-system="DTD/xhtml1-transitional.dtd"
    indent="yes"/>

  <xsl:template match="dictionary">
    <dictionary>
      <xsl:apply-templates select="p[./hw='Own']"/>
    </dictionary>
  </xsl:template>

  <xsl:template match="p[./hw]">
    <xsl:choose>
      <xsl:when test="./hw='Own'">
        <xsl:copy-of select="."/>
        <xsl:apply-templates select="following-sibling::p[1]"/>
        <!-- following-sibling::p[1] is in this case the first p for the wanted entry -->
      </xsl:when>
      <xsl:otherwise>
        <!-- Not applying templates, thus stopping processing at the first hw element after the wanted one -->
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="p">
    <!-- P that is 'content' of a HW 'element' -->
    <!-- Could be any P 'inside' a HW, but template will only be invoked for the 'right' Ps -->
    <xsl:copy-of select="."/>
    <xsl:apply-templates select="p[hw='Own'][following-sibling::p[1]]"/>
    <!-- following-sibling::p[1] is in this case p's for the wanted entry, from the second to the last -->
  </xsl:template>
</xsl:stylesheet>
Avatar billede tejl Nybegynder
15. maj 2002 - 23:13 #7
Ubs.

Jeg glemte at indsætte
<xsl:param name="find" select="'Own'"/>

og benytte p[hw=$find] istedet for p[hw='Own']
Avatar billede janegil Nybegynder
16. maj 2002 - 10:02 #8
Effektiviteten i mitt andre forslag henger nok på hvordan transformasjonsprogrammet implementerer
p[hw][1][hw=$find]].
Hvis det først bygger en liste over alle noder som tilfredstiller p[hw], for så å gjennomgå listen for å se hvilke av dem som har posisjon 1, så tar det jo lang tid.
Men hvis den var smart nok til å smugkikke på [1], så 'visste' den jo at den kan stoppe etter å ha funnet én node som tilfredsstiller p[hw].

Det er jo du som har testet dette, ikke jeg. Men jeg kan ikke begripe at din p[hw='Own'][following-sibling::p[1]] finner noe; jeg svever i den tro at den bare blir applied mellom hw-elementer, der p[hw] burde feile?
Avatar billede tejl Nybegynder
16. maj 2002 - 10:43 #9
Du har ret med hensyn til transformationen. Jeg benyttede Xalan til at processere med, og jeg har fundet ud af at Xalan altid bygger en træstruktur af dokumentet, inden den begynder at parse det. Kender du nogen parser, der ikke bygger en intern repræsentation af dokumentet inden det parses?

Med hensyn til p[hw='Own'][following-sibling::p[1]] så kan jeg ikke forklare det, da jeg først lige er gået igang med at lære mig selv xsl. Ovenstående var et skud i tågen fra min side. Jeg ikke engang fundet ud af hvad det betyder når man skriver p[..][..], altså når man bruger to firkantet klammer i træk.
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