An easier way to write XSL

6 replies [Last post]
Joined: 07/05/2011

This tutorial assumes that you know what XML and XPath is. You don't need to be professional. You just need to know what it is and how to write one.
I'm not very good at English so if you don't understand anything, just post the comment below. Wink
Please pay attention to those uppercase words in the templates because that's where you need to modify.

First, there is a general XSL template:

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="* | comment()">
    <xsl:copy>
      <xsl:copy-of select="@*" />
      <xsl:apply-templates />
    </xsl:copy>
  </xsl:template>
  <!-- COPY YOUR OPERATIONS HERE -->
</xsl:transform>

This XSL simply copy everything and don't change anything. If you don't want to keep the original content, just use compile instead of merge. So next you need to copy the operation templates after that comment.

Operation Template #1: Append child element(s ) to the end of the element

  <xsl:template match="THE XPATH OF THE ELEMENT">
    <xsl:copy>
      <xsl:copy-of select="@*" />
      <xsl:apply-templates />
      <!-- APPEND THE NEW CHILD ELEMENT(S) HERE -->
    </xsl:copy>
  </xsl:template>

Operation Template #2: Append child element(s ) to the top of the element

  <xsl:template match="THE XPATH OF THE ELEMENT">
    <xsl:copy>
      <xsl:copy-of select="@*" />
      <!-- APPEND THE NEW CHILD ELEMENT(S) HERE -->
      <xsl:apply-templates />
    </xsl:copy>
  </xsl:template>

Operation Template #3: Replace the element

  <xsl:template match="THE XPATH OF THE ELEMENT">
    <!-- APPEND THE NEW ELEMENT HERE -->
  </xsl:template>

Operation Template #4: Add/modify attribute(s )

  <xsl:template match="THE XPATH OF THE ELEMENT">
    <xsl:element name="{name()}">
      <xsl:for-each select="THE XPATH OF THE ELEMENT/@*">
        <xsl:attribute name="{name()}">
          <xsl:value-of select="." />
        </xsl:attribute>
      </xsl:for-each>
      <xsl:attribute name="ATTRIBUTE 1 NAME">ATTRIBUTE 1 VALUE</xsl:attribute>
      <xsl:attribute name="ATTRIBUTE 2 NAME">ATTRIBUTE 2 VALUE</xsl:attribute>
      <xsl:attribute name="ATTRIBUTE 3 NAME">ATTRIBUTE 3 VALUE</xsl:attribute>
      <!-- And more attributes here if you want, just use the format above -->
      <xsl:apply-templates />
    </xsl:element>
  </xsl:template>

Operation Template #5: Delete an element or an attribute

  <xsl:template match="THE XPATH OF THE ELEMENT/ATTRIBUTE" />

Please notice that writing comments in XSL will not output to the XML. If you want to do that, just replace <!-- THE COMMENT --> with <xsl:comment>THE COMMENT</xsl:comment>.

Example: Making island1 infinite

Step #1: Remove the /scene/@maxx attribute to make the map infinite.
Step #2: Add tilex="true" to /scene/SceneLayer[@name='bg'] to make the background image tile.
Here's the XSL:

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="* | comment()">
    <xsl:copy>
      <xsl:copy-of select="@*" />
      <xsl:apply-templates />
    </xsl:copy>
  </xsl:template>
  <xsl:template match="/scene/@maxx" />
  <xsl:template match="/scene/SceneLayer[@name='bg']">
    <xsl:element name="{name()}">
      <xsl:for-each select="/scene/SceneLayer[@name='bg']/@*">
        <xsl:attribute name="{name()}">
          <xsl:value-of select="." />
        </xsl:attribute>
      </xsl:for-each>
      <xsl:attribute name="tilex">true</xsl:attribute>
      <xsl:apply-templates />
    </xsl:element>
  </xsl:template>
</xsl:transform>

Hope that helps. Smile

Joined: 12/23/2010

Very nice tutorial! I don't actually know XSL myself so this will help with making merging addins, instead of using the diff tool.

I think this would fit well as a page of its own on the site, so I'll add it later today, with a couple of grammatical fixes. Maybe in the future it can be updated with more operations, if those exist.

Joined: 07/05/2011

The XSLs generated with this method are probably more compatible with other addins.
XML Diff tool generates XPath like /scene[1]/SceneLayer[46] which means the 46th SceneLayer element instead of /scene/SceneLayer[@name='bg']. If a new SceneLayer element inserted at the first of the scene element by other addins, obviously the XSL will no longer work.

Joined: 08/06/2010

Nice tutorial! I agree this should be a book page.

One thing to note: I'd recommend adding things to the end of the file rather than the beginning, so that XSL generated by the diff tool won't break. And in some cases there are enough changes that the diff tool could be necessary: for example, in Another Planet I'm completely replacing the wogc levels with custom ones.

Another Planet finally has an official release! Download chapters 1 through 3 here! Thank you for waiting so long while I kept starting over.

Joined: 07/05/2011

If the changes are large enough, you can use compile instead.

Joined: 12/23/2010

I'm wondering where a book page for this should go. This page kind of explains it a bit, but not really as clearly. Should I replace the explanation with MyGod's explanation, or make a new page and link it, while keeping the current explanation as well?

Joined: 08/06/2010

I think you should replace it. The old one isn't really clear, and it contradicts itself: it says that it will merge with lower-priority addins, then a few paragraphs later that it always merges with the original 2D Boy file. Tongue

Another Planet finally has an official release! Download chapters 1 through 3 here! Thank you for waiting so long while I kept starting over.