Bug Spray
Bug Spray

Reputation: 57

How do I use XSL to add a new element on a certain child node level?

I'm trying to help a friend solve a computer class take-home quiz. I have a simple XML file as follows which defines DVD titles I own on my shelf...

<Inventory>
    <DVD>
        <Name>Captain America</Name>
    </DVD>
    <DVD>
        <Name>Green Lantern</Name>
    </DVD>
    <DVD>
        <Name>Thor</Name>
    </DVD>
</Inventory>

Let's say both "Captain America" and "Thor" are checked-out while "Green Lantern" is still available. I would like to transform the above XML file into the following XML...

<Inventory>
    <DVD>
        <Name>Captain America</Name>
        <Status>Checked-Out</Status>
    </DVD>
    <DVD>
        <Name>Green Lantern</Name>
        <Status>Available</Status>
    </DVD>
    <DVD>
        <Name>Thor</Name>
        <Status>Checked-Out</Status>
    </DVD>
</Inventory>

Can someone share how to utilize XSL to add the Status element to each node? I only have the code snippet below but it copies the same element for all nodes.

<xsl:template match="*">
    <xsl:copy>
        <xsl:copy-of select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="DVD">
    <xsl:copy>
        <xsl:copy-of select="@*|node()"/>
        <Status>Checked-Out</Status>
    </xsl:copy>
</xsl:template>

Thank you very very very much...

Upvotes: 2

Views: 11226

Answers (1)

Daniel Haley
Daniel Haley

Reputation: 52858

What you can do is use an xsl:param to pass the name(s) of the DVD's that are checked out to your XSL and add the <status> based on that. By using xsl:param, you can pass the value from the command line.

Here's an XSLT 2.0 example where the DVD names are pipe delimited in the xsl:param. I use tokenize() in my xsl:template match so that those DVD's get a status of "Checked-Out". All of the other DVD's will get the status of "Available".

XSLT 2.0 Stylesheet:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:param name="checkedOut" select="'Captain America|Thor'"/>

  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="DVD[Name=tokenize($checkedOut,'\|')]">
    <xsl:copy>
      <xsl:apply-templates/>
      <status>Checked-Out</status>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="DVD">
    <xsl:copy>
      <xsl:apply-templates/>
      <status>Available</status>
    </xsl:copy>
  </xsl:template>  

</xsl:stylesheet>

applied to your example XML produces the following output:

<Inventory>
   <DVD>
      <Name>Captain America</Name>
      <status>Checked-Out</status>
   </DVD>
   <DVD>
      <Name>Green Lantern</Name>
      <status>Available</status>
   </DVD>
   <DVD>
      <Name>Thor</Name>
      <status>Checked-Out</status>
   </DVD>
</Inventory>

Hope this helps.

Upvotes: 5

Related Questions