XSLT Transformation von XML

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

  • XSLT Transformation von XML

    Hi
    ich möchte gern ein XML Format ein anderes Format umwandeln.
    Das Urformat sieht so aus:

    Quellcode

    1. <node id="id1" lat="lat" lon="lon">
    2. <node id="id2" lat="lat" lon="lon">
    3. <way>
    4. <nd id="id1">
    5. <nd id="id2">
    6. <tag k="highway">
    7. <tag k="name" v="realname">
    8. </way>

    hier ein beispiel File:
    rafb.net/p/CuTZLM85.html
    Und das Zeilformat soll so aussehen:

    Quellcode

    1. <dict>
    2. <key>LatitudeE6</key>
    3. <integer>lat</integer>
    4. <key>LongitudeE6</key>
    5. <integer>lon</integer>
    6. <key>Name</key>
    7. <string>realname</string>
    8. </dict>

    Wie man also sieht, will ich alle Straßen aus einer GEO XML den Namen, und die Höhen und Längenangaben rausfiltern.
    Die Straßen sind alle in Way per <tag k="highway"> getaggt.
    Es gibt also noch andere tags.
    LÖsung:
    Jedes Way, was mit highway getaggt ist, also <tag k="highway">
    extrahiere davon realname aus <tag k="name" v="realname"> und aus dem mittlere aller nodes die Breiten und Längenangaben.
    Wie kann ich aus einem Childknoten ne Bedingung für die oberen Knoten formulieren. Vorallem, da ja die Tag Dinger so komishc sind.
    Kann mir jemand helfen???
  • und way und dict sind dann äquivalen?. Oder gibts nur ein dic?
    Dann bräuchtest du ja nur über die nodes zu iterieren.

    Ansonsten eigentlich auch kein großes Problem. Erst über way iterieren und dicts erzeugen. Und darin dann über nds und mit id auf die referenzierten nodes springen.

    Siehe
  • sorry wenn ich blöd frage, aber habe gestern erst mit Xml und co angefangen.
    Was genau ist iterieren? Das mit XPath habe ich glaube ich schon verstanden.
    Ways sind sozuagen die Straßen und alle aufgeführten nd's sind die nodes über die die Straße geht.
    Ich möchte also nur eine Node haben. Am Besten die in der Mitte, aber das ist zweitrangig.
    Und der Straßenname und der Geo angaben sollen dann in Dict gepackt werden.
    Was ich halt nicht hingekriegt habe ist über eine Child Bedingung die gleichwertigen Tags auszulesen.
    Also ich muss ja erst ne xsl:when anweisung mit test"tag/@k="highway" machen.
    Und wenn das wahr ist, soll er aus dem gkeuchwertigen tag element, welches k="name" hat, das v-Attribut lesen. Und natürlich die Node ID, und durch diese auf die Geo angaben.
    Nur das hört sich für mich irgendwie unmöglich an.
    Könnte jemand so ne Art Struktur geben??
  • hier hast du eine Struktur... jetzt bist du aber erstmal dran:

    Quellcode

    1. <?xml version="1.0" encoding="iso-8859-1"?>
    2. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    3. <xsl:template match="/">
    4. <html>
    5. <head>
    6. </head>
    7. <body>
    8. <xsl:for-each select="/osm/way">
    9. <xsl:choose>
    10. <xsl:when test="tag/@k = 'highway'">
    11. highway<br/>
    12. </xsl:when>
    13. <xsl:otherwise>
    14. else<br/>
    15. </xsl:otherwise>
    16. </xsl:choose>
    17. </xsl:for-each>
    18. </body>
    19. </html>
    20. </xsl:template>
    21. </xsl:stylesheet>
    Alles anzeigen
  • Hi
    ich denke ich bin auf jeden Fall ein Paar Schritte weiter:
    EDIT: ICh bin noch viel weiter:

    Quellcode

    1. <?xml version="1.0" encoding="iso-8859-1"?>
    2. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    3. <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    4. <xsl:key name="street" match="tag" use="@k" />
    5. <xsl:key name="name" match="tag" use="@k" />
    6. <xsl:key name="node" match="node" use="@id" />
    7. <xsl:template match="/">
    8. <xsl:for-each select="/osm/way">
    9. <xsl:choose>
    10. <xsl:when test="tag/@k = 'highway'">
    11. <xsl:apply-templates select="tag"/>
    12. <xsl:apply-templates select="nd"/>
    13. Count Nodes: <xsl:value-of select="count(nd)"/>
    14. </xsl:when>
    15. </xsl:choose>
    16. </xsl:for-each>
    17. </xsl:template>
    18. <xsl:template match="tag">
    19. <xsl:choose>
    20. <xsl:when test="@k = 'name'">
    21. Street Name: <xsl:value-of select="@v"/>
    22. </xsl:when>
    23. </xsl:choose>
    24. </xsl:template>
    25. <xsl:template match="nd">
    26. Node ID:<xsl:value-of select="@ref"/><xsl:for-each select="key('node',@ref)"> Lat: <xsl:value-of select="@lat"/> Lon: <xsl:value-of select="@lon"/>
    27. </xsl:for-each>
    28. </xsl:template>
    29. </xsl:stylesheet>
    Alles anzeigen

    So bekomme ich eine Ausgabe a la diese hier.

    Quellcode

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. Street Name: Frankfurter Allee
    3. Node ID:20246121 Lat: 52.5157783 Lon: 13.454077
    4. Node ID:29784947 Lat: 52.5151373 Lon: 13.4600538
    5. Node ID:12614667 Lat: 52.5148171 Lon: 13.4632869
    6. Node ID:27459728 Lat: 52.5146598 Lon: 13.4647503
    7. Node ID:20246250 Lat: 52.5145352 Lon: 13.4660848
    8. Node ID:20246248 Lat: 52.5144113 Lon: 13.4674883
    9. Node ID:12614651 Lat: 52.5142142 Lon: 13.4695431
    10. Node ID:29785844 Lat: 52.5140927 Lon: 13.4706331
    11. Node ID:12614666 Lat: 52.5138381 Lon: 13.4733855
    12. Node ID:52762606 Lat: 52.5135684 Lon: 13.4755012
    13. Node ID:12614683 Lat: 52.5134283 Lon: 13.476903
    14. Count Nodes: 11
    15. Street Name: Parkaue
    16. Node ID:29794145 Lat: 52.5168866 Lon: 13.4789195
    17. Node ID:29794146 Lat: 52.5177001 Lon: 13.4786327
    18. Count Nodes: 2
    Alles anzeigen

    EDIT:
    Alles was ich jetzt noch brauche ist die geigente Auswahl einer Node, möglischt der MIttleren, also die zwischen allen liegt, der Mitte Der Straße. Allerdings wäre das wohl zuviel. Es würde mir galube ich schon reichen wenn ich überhaupt mich auf eine einigen kann.
    Und dann brauche ich natürlich das Tag womit ich Tags unverändert ins ZielXML Format schreiben kann. Weil man kann ja nicht direkt Tags schreiben.
    Muss ich dazu die Elementen, Attributen Sets benutzen?
    Gab es nicht da so ein Tag womit man das mchen kann:
    <xsl:veränderenix>
    <dict>
    <meinetags>
    </meinetags>
    </dict>

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

  • ok, das habe ich jetzt auch hinbekomme.
    Das einzigste was mir noch fehlt, ist die eine Position, weil es ja mehrere nd's gibt.
    Gibt es irgendeine Möglichkeit, da was auszuwählen.
    Zum Beispiel den Mittelwert de Höhenangabe und Längenangabe zu machen, und dann den nd nehmen der am nähesten liegt.
    Oder ist das zu kompliziert. Ich weiß ja nicht inwieweit man in XSL sowas machen kann.
    Mir würde ja auch schon reichen wenn ich überhauot mich auf ein nd einigen könnte.
    Any SolutionsS?
  • Die mittlere Koordinate findest du mit dem Durchschnitt. Also Summe / Anzahl an Positionen

    Ansonsten kannst du natürlich immer die erste Position nehmen. Dazu einfach position() = 1 (oder gleich 0??) abfragen
  • ich hab einfahc mal position=2 genommen, denn jede Straße hat ja mindestens 2 knoten.
    Ne ganz andere Frage, ich will das grad mal ausprobieren mit der berlin xml, die gute 180 MB groß ist. Da braucht mein XSLT Prozesoor einfach viel zu lange: 4 Stunden und imme noch nicht fertig.
    Wo gibt es schnellere?
    Ich habe msxsl.exe genommen, weil das unkompliziert aussah.
  • hab meinen Fehler entdeckt, ich habe nicht direkt in das FIle geschrieben sondern die ausgabe abgeschrieben, es geht nun ruckzuck.
    Ich habe trotzdem ein Problem, mein Zielfile ist einwenig zu groß, ich hab dann mal reingeguckt und da sind ein paar Straßen mehrfach bis zu 20 mal drinne. Wie kann ich die rausnehmen, ich würd sie dann nochmal durch ein anderes XSLT schicken odeR?
    Oder gleich in das erste? Hier noch mal mein Momentaner Quellcode. Außerdem habe ich noch das Problem, dass er die nd von ways nimmt die eigentlich nicht mit Highway getaggt sind. Könntest du das nochmlal durchgucken?
    EDIT:
    Ich hab ein neues Stylesheet geschrieben, welches die ohne highway getaggten ways rausnimmt, weil diese ja keine Namen haben
    Kann man das nicht gleich ins alte Stylesheet schreiben? Immerhin wurde das File um ein Drittel kleiner. Nun habe ich aber immernoch das Problem mit den mehrfachen Straßen.
    EDIT2:
    Ich hab herausgefunden warum es die ohne highway getaggten dinger gibt, aufjeden fall lassen die sich nicht vermeiden, ich muss also so oder so ein 2. stylesheet dazunehmen.
    Die Frage belibt also nur noch wie ich Points mit gleichen Namen eliminieren kann.
    DIe Points sehen so aus:

    Quellcode

    1. <dict>
    2. <key>Name</key>
    3. <string>Elsa-Brändström-Straße</string>
    4. <key>LatitudeE6</key>
    5. <integer>52559787</integer>
    6. <key>LongitudeE6</key>
    7. <integer>13418278</integer>
    8. </dict>

    Es gibt also mehrere dicts die beim gleichen key Name den gleichn string enthalten.
    Ist das überhaupt zu realisieren???

    Quellcode

    1. <?xml version="1.0" encoding="iso-8859-1"?>
    2. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    3. <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    4. <xsl:key name="street" match="tag" use="@k" />
    5. <xsl:key name="name" match="tag" use="@k" />
    6. <xsl:key name="node" match="node" use="@id" />
    7. <xsl:strip-space elements="*"/>
    8. <xsl:template match="/">
    9. <plist version="1.0">
    10. <dict><key>Bookmarks</key><array>
    11. <xsl:for-each select="/osm/way">
    12. <xsl:choose><xsl:when test="tag/@k = 'highway'"><dict><xsl:apply-templates select="tag"/><xsl:apply-templates select="nd"/></dict></xsl:when></xsl:choose>
    13. <!--<xsl:choose>
    14. <xsl:when test="count(nd) * -1 &lt;= -10"><key>ZoomLevel</key><integer>13</integer></xsl:when>
    15. <xsl:when test="count(nd) * -1 &lt;= -7"><key>ZoomLevel</key><integer>15</integer> </xsl:when>
    16. <xsl:otherwise><key>ZoomLevel</key><integer>17</integer></xsl:otherwise>
    17. </xsl:choose>--></xsl:for-each></array></dict></plist>
    18. </xsl:template>
    19. <xsl:template match="tag">
    20. <xsl:choose>
    21. <xsl:when test="@k = 'name'">
    22. <key>Name</key><string><xsl:value-of select="@v"/></string>
    23. </xsl:when>
    24. </xsl:choose>
    25. </xsl:template>
    26. <xsl:template match="nd">
    27. <xsl:choose>
    28. <xsl:when test="position() = 2">
    29. <xsl:for-each select="key('node',@ref)">
    30. <key>LatitudeE6</key><integer><xsl:value-of select="((@lat * 1000000) -((@lat * 1000000) mod 1))"/></integer><key>LongitudeE6</key><integer><xsl:value-of select="((@lon * 1000000) -((@lon * 1000000) mod 1))"/></integer>
    31. </xsl:for-each>
    32. </xsl:when>
    33. </xsl:choose>
    34. </xsl:template>
    35. </xsl:stylesheet>
    Alles anzeigen

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von nambrot ()

  • hey ich habe es probiert aber es will einfach nicht funktionieren.
    Hier der entscheidene Teil:

    Quellcode

    1. <xsl:for-each select="/plist/dict/array/dict">
    2. <xsl:sort select="string" order="ascending" data-type="text" />
    3. <xsl:if test="position() != 1">
    4. <xsl:if test="string['position() - 1'] != string[position()]">
    5. <xsl:copy-of select="." />
    6. </xsl:if>
    7. </xsl:if>
    8. </xsl:for-each>

    Er gibt dann einfach nix aus.
    Die Bedingung ist doch richtig oder?
  • hi
    EDIT:
    Komisch, wenn man es mit Choose mit dann funzt das.
    ALso nochmal danke an dich Donut. Wir haben es echt geschafft.
    Ich habe niemals gedacht dass es möglich wär.
    Danke DIR!!!!!
    ich habs mir mir angeguckt und auch nachgeschlagen und eingentlich auch verstanden.
    Es muss doch so sein oder:

    Quellcode

    1. <xsl:for-each select="/plist/dict/array/dict">
    2. <xsl:sort select="string" order="descending" data-type="text" />
    3. <xsl:if test="preceding-sibling::dict/string != string">
    4. <xsl:copy-of select="." />
    5. <xsl:value-of select="preceding-sibling::dict/string" />
    6. </xsl:if>

    Nur irgendwie ignoriert er das und gibt trotzdem dopppelt aus.
    Ich hab dann mal immer nur preceding-silbing ausgegeben und es kam immer das gleiche element für preceding-silbing raus.
    Wieso?