merge two or more xml files, using xslt-3 - xslt-3.0

I have many XML files, which I need to merge into one:
hotel1.xml
<?xml version="1.0" encoding="UTF-8"?>
<menu>
<breakfast_menu>
<food>
<name>Belgian Waffles</name>
<price>$5.95</price>
<description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
<calories>650</calories>
</food>
<food>
<name>Strawberry Belgian Waffles</name>
<price>$7.95</price>
<description>Light Belgian waffles covered with strawberries and whipped cream</description>
<calories>900</calories>
</food>
</breakfast_menu>
</menu>
hotel2:
<?xml version="1.0" encoding="UTF-8"?>
<menu>
<breakfast_menu>
<food>
<name>Berry-Berry Belgian Waffles</name>
<price>$8.95</price>
<description>Light Belgian waffles covered with an assortment of fresh berries and whipped cream</description>
<calories>900</calories>
</food>
</breakfast_menu>
</menu>
hotel3.xml:
<?xml version="1.0" encoding="UTF-8"?>
<menu>
<breakfast_menu>
<food>
<name>French Toast</name>
<price>$4.50</price>
<description>Thick slices made from our homemade sourdough bread</description>
<calories>600</calories>
</food>
<food>
<name>Homestyle Breakfast</name>
<price>$6.95</price>
<description>Two eggs, bacon or sausage, toast, and our ever-popular hash browns</description>
<calories>950</calories>
</food>
</breakfast_menu>
</menu>
I need to first add a value to the name element, in order to know from which file it came from, and merge all xml files.
Desired output:
<?xml version="1.0" encoding="UTF-8"?>
<menu>
<breakfast_menu>
<food>
<name>Belgian Waffles-hotel1</name>
<price>$5.95</price>
<description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
<calories>650</calories>
</food>
<food>
<name>Strawberry Belgian Waffles-hotel1</name>
<price>$7.95</price>
<description>Light Belgian waffles covered with strawberries and whipped cream</description>
<calories>900</calories>
</food>
<food>
<name>Berry-Berry Belgian Waffles-hotel2</name>
<price>$8.95</price>
<description>Light Belgian waffles covered with an assortment of fresh berries and whipped cream</description>
<calories>900</calories>
</food>
<food>
<name>French Toast-hotel3</name>
<price>$4.50</price>
<description>Thick slices made from our homemade sourdough bread</description>
<calories>600</calories>
</food>
<food>
<name>Homestyle Breakfast-hotel3</name>
<price>$6.95</price>
<description>Two eggs, bacon or sausage, toast, and our ever-popular hash browns</description>
<calories>950</calories>
</food>
</breakfast_menu>
</menu>
in a given folder, i need to merge all xml files into one. Just merge their contents. No checks, or updates. Also, i need to keep in the name element, the file each came from, for future reference
Here is my trial.
I need someone more experienced help, in order to use latest xslt-3, and for as xml files that exist in a given folder.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="breakfast_menu">
<xsl:copy>
<xsl:apply-templates select="*"/>
<xsl:apply-templates select="document('hotel1.xml')/menu/breakfast_menu/*" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

There are various ways in XSLT to do this, one would be to try the new xsl:merge instruction, but as I run into problem using that with Saxon 9.8 (see https://saxonica.plan.io/issues/3883 and https://saxonica.plan.io/issues/3884) here is a different way, it seems you simply want to copy all the elements from a certain level, in your case the food elements from the third level; a generic stylesheet to do that which takes a select expression as a static parameter (I have kept it generic as */*/* but you can of course spell it out for your documents as menu/breakfast_menu/food), a URI and a file name pattern for the input files and then is started with the xsl:initial-template (command line option -it for Saxon's command line) is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all"
expand-text="yes"
version="3.0">
<xsl:param name="input-uri" as="xs:string" select="'.'"/>
<xsl:param name="file-pattern" as="xs:string" select="'hotel*.xml'"/>
<xsl:param name="merge-select-expression" as="xs:string" static="yes" select="'*/*/*'"/>
<xsl:param name="xslt-pattern-to-add-file-name" as="xs:string" static="yes" select="$merge-select-expression || '/name'"/>
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:mode on-no-match="shallow-copy" streamable="yes"/>
<xsl:template _match="{$xslt-pattern-to-add-file-name}">
<xsl:comment>Copied this {node-name()} element from {tokenize(document-uri(/), '/')[last()]}</xsl:comment>
<xsl:next-match/>
</xsl:template>
<xsl:template name="xsl:initial-template">
<xsl:sequence select="mf:append-docs(uri-collection($input-uri || '?select=' || $file-pattern))"/>
</xsl:template>
<xsl:function name="mf:append-docs" as="document-node()">
<xsl:param name="doc-uris" as="xs:anyURI+"/>
<xsl:source-document href="{head($doc-uris)}" streamable="yes">
<xsl:apply-templates select="." mode="construct">
<xsl:with-param name="remaining-doc-uris" as="xs:anyURI*" select="tail($doc-uris)" tunnel="yes"/>
</xsl:apply-templates>
</xsl:source-document>
</xsl:function>
<xsl:mode name="construct" on-no-match="shallow-copy" streamable="yes"/>
<xsl:template _match="{string-join(tokenize($merge-select-expression, '/')[position() lt last()], '/')}" mode="construct">
<xsl:param name="remaining-doc-uris" as="xs:anyURI*" tunnel="yes"/>
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:apply-templates/>
<xsl:for-each select="$remaining-doc-uris">
<xsl:source-document href="{.}" streamable="yes">
<xsl:apply-templates _select="{$merge-select-expression}"/>
</xsl:source-document>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
It should work pretty generic by simply adjusting the parameters and perhaps by adjusting the body of the <xsl:template _match="{$xslt-pattern-to-add-file-name}"> template as there I have chosen to output the file name in a comment instead of throwing it into the element's content.
For your three samples in a subdirectory hotel-stackoverflow-test of where the stylesheet append.xsl is and the Saxon command line -it -xsl:.\append.xsl input-uri=hotel-stackoverflow-test file-pattern=hotel*.xml I get the output
<menu>
<breakfast_menu>
<food><!--Copied this name element from hotel1.xml-->
<name>Belgian Waffles</name>
<price>$5.95</price>
<description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
<calories>650</calories>
</food>
<food><!--Copied this name element from hotel1.xml-->
<name>Strawberry Belgian Waffles</name>
<price>$7.95</price>
<description>Light Belgian waffles covered with strawberries and whipped cream</description>
<calories>900</calories>
</food>
<food><!--Copied this name element from hotel2.xml-->
<name>Berry-Berry Belgian Waffles</name>
<price>$8.95</price>
<description>Light Belgian waffles covered with an assortment of fresh berries and whipped cream</description>
<calories>900</calories>
</food>
<food><!--Copied this name element from hotel3.xml-->
<name>French Toast</name>
<price>$4.50</price>
<description>Thick slices made from our homemade sourdough bread</description>
<calories>600</calories>
</food>
<food><!--Copied this name element from hotel3.xml-->
<name>Homestyle Breakfast</name>
<price>$6.95</price>
<description>Two eggs, bacon or sausage, toast, and our ever-popular hash browns</description>
<calories>950</calories>
</food>
</breakfast_menu>
</menu>
The code should use streaming with Saxon 9.8 EE and normal XSLT processing with Saxon 9.8 HE or PE.

Related

Creating (copying) entire records as many times a a tag value demands

i have a few xml records like below example xml. What i try to do is to add as many records as the tag occurrences has, minus 1. (value of occurrences minus 1 will be the records that will be added). If a record has a tag with occurrences value 5, then we must copy this record four more times into the new xml that will be generated. Plus, in the end, an incremental id of all records must be added, like 1,2,3,4,5,6,7 etc
I am now learning xslt 3-0, and would want a solution for xslt 3. I have managed to add an incremental number in all records with xsl count.
<breakfast_menu>
<food>
<name>Belgian Waffles</name>
<occurrences>1</occurrences>
<description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
<calories>650</calories>
</food>
<food>
<name>Strawberry Belgian Waffles</name>
<occurrences>2</occurrences>
<description>Light Belgian waffles covered with strawberries and whipped cream</description>
<calories>900</calories>
</food>
</breakfast_menu>
desired output:
<breakfast_menu>
<food>
<id>1</id>
<name>Belgian Waffles</name>
<occurrences>1</occurrences>
<description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
<calories>650</calories>
</food>
<food>
<id>2</id>
<name>Strawberry Belgian Waffles</name>
<occurrences>2</occurrences>
<description>Light Belgian waffles covered with strawberries and whipped cream</description>
<calories>900</calories>
</food>
<food>
<id>3</id>
<name>Strawberry Belgian Waffles</name>
<occurrences>2</occurrences>
<description>Light Belgian waffles covered with strawberries and whipped cream</description>
<calories>900</calories>
</food>
</breakfast_menu>
Here is a two step transformation:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:template match="breakfast_menu">
<xsl:copy>
<xsl:variable name="food">
<xsl:apply-templates mode="duplicate"/>
</xsl:variable>
<xsl:apply-templates select="$food/food"/>
</xsl:copy>
</xsl:template>
<xsl:mode name="duplicate" on-no-match="shallow-copy"/>
<xsl:template mode="duplicate" match="food">
<xsl:copy-of select="(1 to occurrences) ! current()"/>
</xsl:template>
<xsl:template match="food">
<xsl:copy>
<id><xsl:number/></id>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output indent="yes"/>
</xsl:stylesheet>

How to map value of one xml to another one in Python

I need to make XML out of response in XML format.
For some fields, I need to be able to change the value. I also need to remove all fields that are not mapped.
I get responses that look like this
<response>
<DOCUMENTS>
<DOCUMENT>
<KODA>AA</KODA>
<ITEMS>
<ITEM>B</ITEM>
<ITEM>C</ITEM>
</ITEMS>
</DOCUMENT>
</DOCUMENTS>
</response>
and want to make of it something that looks like below
<EXPORT>
<DOCUMENTS>
<DOCUMENT>
<KODDZ>SS</KODDZ>
<VALUES>
<VALUE>B</VALUE>
<VALUE>C</VALUE>
</VALUES>
</DOCUMENT>
</DOCUMENTS>
</EXPORT>
I have been trying using the XSLT example from this question but without success.
Basically what would be best for me would be a solution that takes some kind of map of fields for example:
map_of_values = {"response/DOCUMENTS/DOCUMENT/KODA":"EXPORT/DOCUMENTS/DOCUMENT/KODZA",
"response/DOCUMENTS/DOCUMENT/ITEMS/ITEM":EXPORT/DOCUMENTS/DOCUMENT/VALUES/VALUE}
What would be the best way to achieve a static map kind of solution?
In terms of XSLT you seem to want something along the lines of
<xsl:template match="response">
<EXPORT>
<xsl:apply-templates/>
</EXPORT>
</xsl:template>
<xsl:template match="KODA">
<KODDZ>
<xsl:apply-templates/>
</KODDZ>
</xsl:template>
<xsl:template match="KODA/text()[. = 'AA']">
<xsl:text>SS</xsl:text>
</xsl:template>
<xsl:template match="ITEMS">
<VALUES>
<xsl:apply-templates/>
</VALUES>
</xsl:template>
<xsl:template match="ITEM">
<VALUE>
<xsl:apply-templates/>
</VALUE>
</xsl:template>
plus the identity transformation template, of course.

"Reserved namespace" error occurs when chaining named templates with "xsl:original" in XSLT-3.0

I'm trying to chain named templates in XSLT 3.0 using the "xsl:original" feature, but I get a reserved-name namespace error.
As an example, I use a named template add-atts that is defined in two included stylesheets:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs" version="3.0">
<xsl:template match="/">
<root>
<xsl:apply-templates select="root/line"/>
</root>
</xsl:template>
<xsl:template match="line">
<xsl:copy>
<xsl:call-template name="add-atts"/> <!-- USED HERE -->
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<xsl:import href="add-foo.xsl"/> <!-- DEFINED HERE -->
<xsl:import href="add-bar.xsl"/> <!-- DEFINED HERE -->
</xsl:stylesheet>
The first included stylesheet has a named template that adds a #foo attribute:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs" version="3.0">
<xsl:template name="add-atts">
<xsl:attribute name="att1">foo</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
The second included stylesheet has a named template of the same name (which takes precedence due to ordering) that adds a #bar attribute, then attempts to call the overridden template from the previous file:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs" version="3.0">
<xsl:template name="add-atts">
<xsl:attribute name="att2">bar</xsl:attribute>
<xsl:call-template name="xsl:original"/> <!-- HERE -->
</xsl:template>
</xsl:stylesheet>
When I run this on the following input file
<root>
<line>1</line>
<line>2</line>
<line>3</line>
</root>
I get the following error:
$ java -jar .../Saxon-HE-9.9.1-4.jar in.xml trans.xsl
Static error in xsl:call-template/#name on line 8 column 46 of add-bar.xsl:
XTSE0080: Namespace prefix xsl refers to a reserved namespace
Errors were reported during stylesheet compilation
The xsl: namespace is declared, the XSLT version is set to 3.0, and the usage is the same as what's shown in this example from the deprecated XSL-LIST mailing list. What am I missing?
(The actual intent is to chain named templates when creating plugins for the DITA Open Toolkit.)
Thanks in advance!
The functionality exists in the context of the new XSLT 3 feature of packages, see https://www.w3.org/TR/xslt-30/#refer-to-overridden. Neither the spec nor that thread you have linked to seem to introduce this functionality in the context of simply xsl:imports.
To give you an example on how this can be used in XSLT 3 with packages, suppose you have a first package
<?xml version="1.0" encoding="UTF-8"?>
<xsl:package
name="http://example.com/packages/ex1"
package-version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:template name="add-atts" visibility="public">
<xsl:attribute name="att1">foo</xsl:attribute>
</xsl:template>
</xsl:package>
then you can write a second package overriding that named template and making use of <xsl:call-template name="xsl:original"/>:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:package
name="http://example.com/packages/ex2"
package-version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:use-package name="http://example.com/packages/ex1">
<xsl:override>
<xsl:template name="add-atts" visibility="public">
<xsl:attribute name="att2">bar</xsl:attribute>
<xsl:call-template name="xsl:original"/>
</xsl:template>
</xsl:override>
</xsl:use-package>
</xsl:package>
Finally you can use the second package:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs" version="3.0">
<xsl:use-package name="http://example.com/packages/ex2"></xsl:use-package>
<xsl:output indent="yes"/>
<xsl:template match="/">
<root>
<xsl:apply-templates select="root/line"/>
</root>
</xsl:template>
<xsl:template match="line">
<xsl:copy>
<xsl:call-template name="add-atts"/> <!-- USED HERE -->
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
With Saxon from the command line, you would need to make sure you give the list of file names of the two packages with the -lib option e.g. -lib:package1.xsl;package2.xsl on Windows and -lib:package1.xsl:package2.xsl on Linux, when you run the main stylesheet.

inspect an xml file, and generate a report on duplicate elements using xslt-3

Given the following xml as input, i try to create a report using xslt-3
<breakfast_menu>
<food>
<name>01</name>
<price>$5.95</price>
<description>Two of our famous Belgian Waffles with plenty of real maple [syrup]</description>
<calories>650</calories>
</food>
<food>
<name>01</name>
<price>$7.95</price>
<description>Two of our famous Belgian Waffles with plenty of real maple [syrup]</description>
<calories>350</calories>
</food>
<food>
<name>02</name>
<price>$8.95</price>
<description>Light Belgian waffles covered with an assortment of fresh berries and whipped cream</description>
<calories>900</calories>
</food>
<food>
<name>03</name>
<price>$4.50</price>
<description>Thick slices made from our homemade sourdough bread</description>
</food>
<food>
<name>04</name>
<price>$6.95</price>
<description>Light Belgian waffles covered with an assortment of fresh berries and whipped cream</description>
<calories>100</calories>
</food>
<food>
<name>05</name>
<price>$7.95</price>
<description>Two of our famous Belgian Waffles with plenty of real maple [syrup]</description>
<calories>250</calories>
</food>
</breakfast_menu>
to identify all menu elements, that have the same description.
Please note that not all menu nodes have a calories element, thus a null text value may be inserted in the generated corresponding tab column.
From the above example, i try to create a tsv report that would look like (sorted by the description element):
01\tTwo of our famous Belgian Waffles with plenty of real maple [syrup]\t650
01\tTwo of our famous Belgian Waffles with plenty of real maple [syrup]\t350
05\tTwo of our famous Belgian Waffles with plenty of real maple [syrup]\t250
02\tLight Belgian waffles covered with an assortment of fresh berries and whipped cream\t900
02\tLight Belgian waffles covered with an assortment of fresh berries and whipped cream\t100
my trial using xsl v2:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output indent="yes"/>
<xsl:key name="ids" match="*[#description]" use="#description"/>
<xsl:template match="/">
<duplicates>
<xsl:apply-templates select="//*[#description]"/>
</duplicates>
</xsl:template>
<xsl:template match="*[#description]">
<xsl:if test="count(key('ids', #description)) > 1">
<duplicate
id="{#description}"
dup-count="{count(key('ids', #description))}"
node-xpath="{string-join((for $node in ancestor::* return concat($node/name(),'[', count($node/preceding-sibling::*[name() = $node/name()])+1, ']'),concat(name(),'[', count(preceding-sibling::*[name() = current()/name()]) + 1, ']')
),'/')}">
</duplicate>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
You can use for-each-group to group-by="description", then you can output the text format using value-of separator=" ":
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0">
<xsl:output method="text" />
<xsl:template match="breakfast_menu">
<xsl:for-each-group select="food" group-by="description">
<xsl:sort select="current-grouping-key()"/>
<xsl:if test="current-group()[2]">
<xsl:apply-templates select="current-group()"/>
</xsl:if>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="food">
<xsl:value-of select="name, description, string(calories)" separator=" "/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/3NzcBsV

search and replace an element, using xslt 3, the replacement phrase is the same

while i have as input an xml file like:
<?xml version="1.0"?>
<catalog>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.</description>
</book>
<book id="bk102">
<author>Ralls, Kim</author>
<title>Midnight Rain</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-12-16</publish_date>
<description>A former architect battles corporate zombies,
an evil sorceress, and her own childhood to become queen
of the world.</description>
</book>
<book id="bk103">
<author>Corets, Eva</author>
<title>Maeve Ascendant</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-11-17</publish_date>
<description>After the collapse of a nanotechnology
society in England, the young survivors lay the
foundation for a new society.</description>
</book>
</catalog>
and i try to find the best way to have the following info in a file, or in the xsl itself:
value to search for:
An in-depth look at creating applications with XML.
add location:
on the self
value to search for:
A former architect battles corporate zombies, an evil sorceress, and her own childhood to become queen of the world.
add location:
on the self
so if i made a comma separated input file, it would look like:
"An in-depth look at creating applications with XML.","on the self"
"A former architect battles corporate zombies, an evil sorceress, and her own childhood to become queen of the world.","on the self"
i have tried with xslt 2, but i keep getting errors like a sequence of more than one item is not allowed as the value of variable $search_phrase...
Desired output:
<?xml version="1.0"?>
<catalog>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>to be checked</description>
<location>on the self</location>
</book>
<book id="bk102">
<author>Ralls, Kim</author>
<title>Midnight Rain</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-12-16</publish_date>
<description>to be checked</description>
<location>on the self</location>
</book>
<book id="bk103">
<author>Corets, Eva</author>
<title>Maeve Ascendant</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-11-17</publish_date>
<description>After the collapse of a nanotechnology
society in England, the young survivors lay the
foundation for a new society.</description>
</book>
</catalog>
Could someone give me an example with xslt-3.0 where probably i could replace the above phrases, and add the needed elements as well, wherever there is a match?
What i need to do:
in the full xml file, there are many records that can have the same description. I also need to make an exact match on the description: The phrase
"An in-depth look at creating applications with XML, authored by ..."
should not be matched. And in my case, i have also a description where the difference is only the case for instance, "an in-depth look at creating applications with XML." should not be also matched. Since in my code i use lowercase, this may also be the problem, but not sure... Whenever there is a match, the location specified along the search term, must be added into the location element, which currently does not exist in any record in the xml.
Here is a suggestion on how to compare the description elements to a sequence of strings passed in as a parameter (but you could of well read it in from a file):
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
expand-text="yes"
version="3.0">
<xsl:param name="new" as="xs:string" select='"on the self"'/>
<xsl:param name="replace" as="xs:string" select="'to be checked'"/>
<xsl:param name="search" as="xs:string*"
select='"An in-depth look at creating applications with XML.",
"A former architect battles corporate zombies, an evil sorceress, and her own childhood to become queen of the world."'/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="description[. = $search]">
<xsl:copy>{$replace}</xsl:copy>
<location>{$new}</location>
</xsl:template>
</xsl:stylesheet>
Works fine at http://xsltfiddle.liberty-development.net/eiQZDbk, but only after editing the sample to have all description data on one line.
If that is not the case then changing the template to
<xsl:template match="description[normalize-space() = $search]">
<xsl:copy>{$replace}</xsl:copy>
<location>{$new}</location>
</xsl:template>
should help: http://xsltfiddle.liberty-development.net/eiQZDbk/1
If you have several terms to relate to each other than some XML format seems be more appropriate to structure the data, so in
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
expand-text="yes"
version="3.0">
<xsl:param name="data-url" as="xs:string" select="'data.xml'"/>
<!-- if you want to load from a file use xsl:param name="replacement-doc" select="doc($data-url)" -->
<xsl:param name="replacement-doc">
<root>
<search>
<term>An in-depth look at creating applications with XML.</term>
<replacement>to be checked</replacement>
<new>on the self</new>
</search>
<search>
<term>A former architect battles corporate zombies, an evil sorceress, and her own childhood to become queen of the world.</term>
<replacement>whatelse</replacement>
<new>something</new>
</search>
</root>
</xsl:param>
<xsl:key name="search" match="search" use="term"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="description[key('search', normalize-space(), $replacement-doc)]">
<xsl:variable name="search" select="key('search', normalize-space(), $replacement-doc)"/>
<xsl:copy>{$search/replacement}</xsl:copy>
<location>{$search/new}</location>
</xsl:template>
</xsl:stylesheet>
I have made some suggestion to do that and have adapted the template. Online sample is at http://xsltfiddle.liberty-development.net/eiQZDbk/2. As indicated there in a comment you can adapt that approach to load the data from a separate file instead of keeping it inline in the XSLT.

Resources