Position als Attribut am Knoten

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Position als Attribut am Knoten

    Hallo zusammen!

    Ich habe ein (für mich) schwieriges Problem und hoffe, dass mir hier ein Profi helfen kann.

    Ich möchte ein XML so transformieren, dass die Eingabe = Ausgabe und bestimmte Elemente ein neues Attribut erhalten. Der neue Attribut-Wert soll die Position des aktuellen Knoten (bezogen auf ein übergeordnetes Element) beinhalten.
    Beispiel:
    Es soll an alle Elemente beginnend mit "Text" ein Attribut geschrieben werden. Der Attributwert besagt das wievielste Text*-Element innerhalb eines Kapitels es ist. Text kann dabei an verschiedensten Stellen untehalb von "Kapitel"vorkommen.
    Eingabemenge:

    Quellcode

    1. <?xml version="1.0" encoding="ISO-8859-1"?>
    2. <Schrank>
    3. <Buch>
    4. <Kapitel>
    5. <Text1/>
    6. <Text2/>
    7. <Text2/>
    8. <Bild/>
    9. <Tabelle>
    10. <Text1/>
    11. <Text2/>
    12. <TextXYZ/>
    13. </Tabelle>
    14. </Kapitel>
    15. <Kapitel>
    16. <Text1/>
    17. <Text2/>
    18. <Text2/>
    19. <Tabelle>
    20. <Text1/>
    21. <Text2/>
    22. <TextXYZ/>
    23. </Tabelle>
    24. </Kapitel>
    25. </Buch>
    26. </Schrank>
    Alles anzeigen




    Ausgabe:

    Quellcode

    1. <?xml version="1.0" encoding="ISO-8859-1"?>
    2. <Schrank>
    3. <Buch>
    4. <Kapitel>
    5. <Text1 count="1"/>
    6. <Text2 count="2"/>
    7. <Text2 count="3"/>
    8. <Bild/>
    9. <Tabelle>
    10. <Text1 count="4"/>
    11. <Text2 count="5"/>
    12. <TextXYZ count="6"/>
    13. </Tabelle>
    14. </Kapitel>
    15. <Kapitel>
    16. <Text1 count="1"/>
    17. <Text2 count="2"/>
    18. <Text2 count="3"/>
    19. <Bild/>
    20. <Tabelle>
    21. <Text1 count="4"/>
    22. <Text2 count="5"/>
    23. <TextXYZ count="6"/>
    24. </Tabelle>
    25. </Kapitel>
    26. </Buch>
    27. </Schrank>
    Alles anzeigen



    Ich konnte das Problem hoffentlich ausreichend beschreiben und hoffe auf schnelle Hilfe.
    Als Parser verwende ich dem SAXON8 (xslt2.0)

    Danke und besten Gruß
    ti-schmi
  • Ich habe eine Lösung gefunden. SAXON kann Variablen ändern.

    Hier das xsl zum Beispiel.

    Quellcode

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:saxon="http://saxon.sf.net/" version="2.0" extension-element-prefixes="saxon">
    3. <xsl:output method="xml" encoding="UTF-8"/><xsl:variable name="s_pos" saxon:assignable="yes" select="0"/>
    4. <xsl:template match="node()|@*"><xsl:choose><xsl:when test="matches (name(),'Kapitel' )"><saxon:assign name="s_pos" select="0"/><xsl:copy>
    5. <xsl:attribute name="s_pos">
    6. <xsl:value-of select="$s_pos"/>
    7. </xsl:attribute>
    8. <xsl:apply-templates select="@*|node()"/>
    9. </xsl:copy></xsl:when><xsl:when test="starts-with(name(),'Text') "><saxon:assign name="s_pos" select="$s_pos+1"/><xsl:copy>
    10. <xsl:attribute name="s_pos">
    11. <xsl:value-of select="$s_pos"/>
    12. </xsl:attribute>
    13. <xsl:apply-templates select="@*|node()"/>
    14. </xsl:copy></xsl:when><xsl:otherwise><xsl:copy>
    15. <xsl:apply-templates select="@*|node()"/>
    16. </xsl:copy></xsl:otherwise></xsl:choose>
    17. </xsl:template>
    18. </xsl:stylesheet>
    Alles anzeigen
  • geht auch mit andern Parser durch saxon unabhängig und schneller

    ein Test mit
    vorrige Lösung
    saxon 8.7 Durchschnitt 750-810 Milisekunden


    neue Lösung
    saxon 8.7 Durchschnitt 450-510 Millisekunden
    xalan 2.5 Durchschnitt über 3 Sekunden
    msxml 6 Durchschnitt 150-200 Millisekunden

    XML-Quellcode

    1. <?xml version="1.0"?>
    2. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    3. <xsl:output method="xml" indent="yes"/>
    4. <xsl:template match="/">
    5. <xsl:apply-templates select="Schrank"/>
    6. </xsl:template>
    7. <xsl:template match="Schrank">
    8. <Schrank>
    9. <xsl:apply-templates select="Buch"/>
    10. </Schrank>
    11. </xsl:template>
    12. <xsl:template match="Buch">
    13. <Buch>
    14. <xsl:apply-templates select="Kapitel"/>
    15. </Buch>
    16. </xsl:template>
    17. <xsl:template match="Kapitel">
    18. <Kapitel>
    19. <xsl:for-each select="*">
    20. <xsl:variable name="kn" select="local-name()"/>
    21. <xsl:element name="{$kn}">
    22. <xsl:if test="starts-with(name(),'Text')">
    23. <xsl:attribute name="pos">
    24. <xsl:value-of select="position()"/>
    25. </xsl:attribute>
    26. </xsl:if>
    27. <xsl:if test="count(descendant::*[name()])">
    28. <xsl:variable name="qz" select="count(child::*[starts-with(name(),'Text')])-1"/>
    29. <xsl:for-each select="descendant::*[name()]">
    30. <xsl:variable name="kn1" select="local-name()"/>
    31. <xsl:element name="{$kn1}">
    32. <xsl:if test="starts-with(name(),'Text')">
    33. <xsl:attribute name="pos">
    34. <xsl:value-of select="position()+$qz"/>
    35. </xsl:attribute>
    36. </xsl:if>
    37. </xsl:element>
    38. </xsl:for-each>
    39. </xsl:if>
    40. </xsl:element>
    41. </xsl:for-each>
    42. </Kapitel>
    43. </xsl:template>
    44. </xsl:stylesheet>
    Alles anzeigen

    Hoffe auf eine Rückmeldung
    Helmut Hagemann
    Derjenige, der sagt: Das geht nicht, soll den nicht stören, der's gerade tut.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von xml_looser ()

  • waren noch ein paar Fehler drinnen

    jetzt hoffentlich fehlerfrei



    XML-Quellcode

    1. <?xml version="1.0"?>
    2. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    3. <xsl:output method="xml" indent="yes"/>
    4. <xsl:template match="/">
    5. <xsl:apply-templates select="Schrank"/>
    6. </xsl:template>
    7. <xsl:template match="Schrank">
    8. <Schrank>
    9. <xsl:apply-templates select="Buch"/>
    10. </Schrank>
    11. </xsl:template>
    12. <xsl:template match="Buch">
    13. <Buch>
    14. <xsl:apply-templates select="Kapitel"/>
    15. </Buch>
    16. </xsl:template>
    17. <xsl:template match="Kapitel">
    18. <Kapitel>
    19. <xsl:for-each select="*">
    20. <xsl:variable name="kn" select="local-name()"/>
    21. <xsl:element name="{$kn}">
    22. <xsl:if test="starts-with(name(),'Text')">
    23. <xsl:attribute name="pos">
    24. <xsl:value-of select="count(preceding-sibling::*[starts-with(name(),'Text')])+count(preceding-sibling::*[not(starts-with(name(),'Text'))]/child::*[starts-with(name(),'Text')])+1"/>
    25. </xsl:attribute>
    26. </xsl:if>
    27. <xsl:if test="count(descendant::*[name()])">
    28. <xsl:variable name="qz" select="count(preceding-sibling::*[starts-with(name(),'Text')])"/>
    29. <xsl:for-each select="descendant::*[name()]">
    30. <xsl:variable name="kn1" select="local-name()"/>
    31. <xsl:element name="{$kn1}">
    32. <xsl:if test="starts-with(name(),'Text')">
    33. <xsl:attribute name="pos">
    34. <xsl:value-of select="position()+$qz+count(../preceding-sibling::*[not(starts-with(name(),'Text'))]/child::*[starts-with(name(),'Text')])"/>
    35. </xsl:attribute>
    36. </xsl:if>
    37. </xsl:element>
    38. </xsl:for-each>
    39. </xsl:if>
    40. </xsl:element>
    41. </xsl:for-each>
    42. </Kapitel>
    43. </xsl:template>
    44. </xsl:stylesheet>
    Alles anzeigen
    Helmut Hagemann
    Derjenige, der sagt: Das geht nicht, soll den nicht stören, der's gerade tut.