Hello,

I have the following code in XML:

<?xml version="1.0" encoding="UTF-8"?>
<agency>
    <destinations>
        <destination id="bel">Belize</destination>
        <destination id="mad">Madeira</destination>
        <destination id="per">Peru</destination>
    </destinations>
    <traveler id="coelho">
        <passport>P-123456-08</passport>
        <name>Pedro Coelho</name>
        <born>1964-10-05</born>
        <trip>
            <start>2013-07-01</start>
            <end>2013-07-15</end>
            <itinerary destination="bel">
                Viagem em classe executiva para Belize via Frankfurt.
            </itinerary>
            <plane date="2013-07-01">
                Pedir refeição vegan.
                <airport>Barajas</airport>
                Alertar assistente antes da próxima ligação.
            </plane>
            <plane date="2013-07-01">
                Confirmado. Comparecer com 3 horas de antecedência.
                <airport>Frankfurt</airport>
            </plane>
                <hotel date="2013-07-01">Beach Resort</hotel>
                <hotel date="2013-07-08">Mountain Inn</hotel>
        </trip>
    </traveler>
    <traveler id="leite">
        <passport>P-456789-09</passport>
        <born>1970-12-25</born>
        <name>Fernanda Leite</name>
    </traveler>
</agency>

And the result in an xml file:

<?xml version="1.0" encoding="UTF-8"?>
<destinations>
  <destination id="bel">
    <trip start="2013-07-01" end="2013-07-15">
       <itinerary>
          Viagem em classe executiva para Belize via Frankfurt.
       </itinerary>
       <planes>2</planes>
     </trip>
  </destination>
  <destination id="mad"/>
  <destination id="per"/>
</destinations>

And I help to the xsl file that generates de result xml file. Somebody can help me?

Dani AI

Generated

A straightforward, robust way to produce the desired XML is to index trips by their itinerary/@destination (an XSLT key) and then walk the original destinations/destination list emitting any matching trips. That avoids fragile ../../ relative paths and makes counting planes simple (count(plane) inside the trip context). The XSLT below is XSLT 1.0 and produces a <destinations> root with a <destination id="..."> and one <trip> element per matching traveler/trip.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
  <xsl:key name="trips-by-dest" match="traveler/trip" use="itinerary/@destination"/>

  <xsl:template match="/agency">
    <destinations>
      <xsl:apply-templates select="destinations/destination"/>
    </destinations>
  </xsl:template>

  <xsl:template match="destination">
    <destination>
      <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
      <xsl:for-each select="key('trips-by-dest', @id)">
        <trip start="{start}" end="{end}">
          <itinerary><xsl:value-of select="normalize-space(itinerary)"/></itinerary>
          <planes><xsl:value-of select="count(plane)"/></planes>
        </trip>
      </xsl:for-each>
    </destination>
  </xsl:template>
</xsl:stylesheet>

Notes and pitfalls (based on the thread):

  • 's approach almost reached the goal but used extra .. navigation and an internal test that mis-scoped start/end and plane counts; in a trip context simply use start, end and count(plane).
  • Watch simple typos: ends vs end will produce wrong attribute names.
  • Whitespace in the itinerary node can be normalized with normalize-space() (shown) or preserved with xsl:copy-of select="itinerary/node()" if exact formatting is needed.
  • If you need to aggregate across multiple travelers into a single trip-per-destination (for example sum planes across all trips to the same destination), prefer XSLT 2.0 grouping (xsl:for-each-group) or implement a small summing template in XSLT 1.0.

This keeps the transformation predictable and easy to reason about while matching the original intent posted by and addressing the issues in 's attempt.

Recommended Answers

All 2 Replies

I am not getting your doubt.
Your output came from an xsl file.so what do u want to do now?

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
    <xsl:template match="/">
        <destinations>
            <xsl:apply-templates select="agency/destinations"/>
        </destinations>
    </xsl:template>
    <xsl:template match="destinations">
        <xsl:apply-templates select="destination"/>
    </xsl:template>

    <xsl:template match="destination">
        <xsl:variable name="id" select="@id"/>
        <destination>
            <xsl:attribute name="id">
                <xsl:value-of select="@id"/>
            </xsl:attribute>
            <xsl:apply-templates select="../../traveler[./trip/itinerary/@destination = $id]">
                <xsl:with-param name="id" select="$id"/>
            </xsl:apply-templates>
        </destination>
    </xsl:template>
    <xsl:template match="traveler">
        <xsl:param name="id"/>
        <xsl:if test="../traveler/trip/itinerary/@destination=$id">
            <trip>
                <xsl:attribute name="start">
                    <xsl:value-of select="../traveler/trip/start"/>
                </xsl:attribute>
                <xsl:attribute name="ends">
                    <xsl:value-of select="../traveler/trip/end"/>
                </xsl:attribute>
                <itinerary>
                    <xsl:value-of select="../traveler/trip/itinerary"/>
                </itinerary>
                <planes>
                    <xsl:value-of select="count(../traveler/trip/plane)"/>
                </planes>
            </trip>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.