dom
dom

Reputation: 356

xml to xml copy with replace of [field]

hi guys so ive been having a bit of trouble with his one i want to do a complete copy of an xml and replace of a fields within the data this is the code i have been using but it only transforms the first field and doesnt copy the xml im using eclipse with the default xsl transformation to do the work as it seems its the only processor i can get working correctly anyway here is the xsl template:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
    <xsl:variable name="replacedURL">
        <xsl:call-template name="string-replace-all">
            <xsl:with-param name="text" select="/hotels/hotel/hotel_link/text()"/>
            <xsl:with-param name="replace" select="'[[PARTNERID]]'"/>
            <xsl:with-param name="by" select="'13252'"/>
        </xsl:call-template>
    </xsl:variable>
    <xsl:value-of select="$replacedURL"/>
</xsl:template>
<xsl:template name="string-replace-all">
    <xsl:param name="text"/>
    <xsl:param name="replace"/>
    <xsl:param name="by"/>
    <xsl:choose>
        <xsl:when test="contains($text, $replace)">
            <xsl:value-of select="substring-before($text,$replace)"/>
            <xsl:value-of select="$by"/>
            <xsl:call-template name="string-replace-all">
                <xsl:with-param name="text" select="substring-after($text,$replace)"/>
                <xsl:with-param name="replace" select="$replace"/>
                <xsl:with-param name="by" select="$by"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$text"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>
</xsl:stylesheet>

then this is a sample of the xml

<hotel>
<hotel_ref>235128</hotel_ref>
<hotel_name>Afghanistan Dolores test - non bookable</hotel_name>
<hotel_star>2</hotel_star>
<hotel_address>afghanistan test</hotel_address>
<hotel_city>afghanistan</hotel_city>
<hotel_pcode /><hotel_county />
<hotel_country>Afghanistan</hotel_country>
<hotel_description>hotel description text</hotel_description>
 <alternate_description>hotel description text</alternate_description>
 <hotel_directions>kjlaklka</hotel_directions>
 <alternate_directions>kjlaklka</alternate_directions>
<hotel_link> http://www.website.com/en/p[[PARTNERID]]/hotel-reservations/235128_afghanistan-dolores-test-non-bookable-afghanistan.aspx</hotel_link>
<customerrating>0</customerrating>
<PricesFrom>10.0000</PricesFrom>
<MaxPrice>800.00</MaxPrice>
<CurrencyCode>GBP</CurrencyCode>
<images />
<geo_code><lat>34.53824</lat><long>69.18640</long></geo_code>
<hotel_facilities />
<checkin_time>12/07/2011 14:00:00</checkin_time>
<checkout_time>12/07/2011 11:00:00</checkout_time>
 <cancellationpolicy>2 days prior to stay</cancellationpolicy>
<cancellationtext /><accommodation_type /><hotel_appeals />
<hotel_star_accreditor />
<hotel_total_rooms>45</hotel_total_rooms>
<hotel_credit_cards>
<CreditCard><credit_card_id>4</credit_card_id><credit_card_name>American Express</credit_card_name></CreditCard><CreditCard><credit_card_id>5</credit_card_id><credit_card_name>Switch/Maestro</credit_card_name></CreditCard><CreditCard><credit_card_id>1</credit_card_id><credit_card_name>Visa/Delta</credit_card_name></CreditCard><CreditCard><credit_card_id>2</credit_card_id> <credit_card_name>Mastercard</credit_card_name></CreditCard></hotel_credit_cards>  
<hotel_city_taxes><CityTax><Type /><Value /><OptedIn /><IsCityTaxArea /></CityTax>
</hotel_city_taxes> 
</hotel>

the whole file is around 500 megabytes would i need a special proccessor to do this or would eclipses built in xsl transform do the job

Upvotes: 0

Views: 1304

Answers (1)

Tomalak
Tomalak

Reputation: 338208

Copy everything while modifying only one little piece is always a case for the identity template:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

  <!-- ...except for the text in <hotel_link> elements: -->
  <xsl:template match="hotel_link/text()">
    <xsl:call-template name="string-replace-all">
      <xsl:with-param name="text"    select="."/>
      <xsl:with-param name="replace" select="'[[PARTNERID]]'"/>
      <xsl:with-param name="by"      select="'13252'"/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="string-replace-all">
    <xsl:param name="text"/>
    <xsl:param name="replace"/>
    <xsl:param name="by"/>
    <xsl:choose>
      <xsl:when test="contains($text, $replace)">
        <xsl:value-of select="substring-before($text,$replace)"/>
        <xsl:value-of select="$by"/>
        <xsl:call-template name="string-replace-all">
          <xsl:with-param name="text" select="substring-after($text,$replace)"/>
          <xsl:with-param name="replace" select="$replace"/>
          <xsl:with-param name="by" select="$by"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$text"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

(The string-replace-all template has been taken from this answer.)

That being said, if your input file is 500 MB, you should not use an XSLT transformation, as this builds a complete DOM of the input in memory before it can begin. A DOM is always a lot larger than the XML document it is based on, so you could get into memory trouble here. Of course you can try it anyway.

You should write a small SAX parser instead. This will be faster and more memory-efficient.

Upvotes: 1

Related Questions