XSL: how to use document() to read xml files in a folder - xslt

I need to compare xml files from two folders and collect those xml elements that only show up in one of the xml file.
The xml files in two folder has same file name.
Below is the sample of what I want to do:
old/booklist1.xml
<books>
<book #type="fiction">
<isn>12345678</isn>
<name>xxxx</name>
</book>
</books>
new/booklist1.xml
<books>
<book #type="fiction">
<isn>12345678</isn>
<name>xxxx</name>
</book>
<book #type="history">
<isn>23456789</isn>
<name>yyyyy</name>
</book>
</books>
I will need the output of the booklist1.xml as the below:
<books>
<book #type="history">
<isn>23456789</isn>
<name>yyyyy</name>
</book>
</books>
I have below findDiff.xsl that works when I specify / hardcode the xml file name:
<xsl:key name="book" match="book" use="." />
<xsl:template match="/books">
<xsl:copy>
<xsl:copy-of select="book[not(key('book', ., document('old_booklist1.xml')))]"/>
</xsl:copy>
</xsl:template>
The fidDiff.xsl current is associated with new/booklist1.xml and I copied the old/booklist1.xml to the same folder with new/booklist1.xml and made the name as old_booklist1.xml and above xsl works with the hard coded uri.
I have to loop throw xml file in folder new and then compare it with the same named xml file in folder old.
I am thinking to use the following way to build the xml file URI:
loop in the new and get the file uri
build the file uri for xml file in old folder
<xsl:variable name="xmlPath" select="document-uri()"/>
<xsl:variable name="compareWithPath" select=" replace($xmlFilePath, 'new', 'old')"/>
then pass the compareWithPath to below template:
<xsl:template match="/books">
<xsl:copy>
<xsl:copy-of select="book[not(key('book',., document($compareWithPath)))]"></xsl:copy-of>
</xsl:copy>
</xsl:template>
But I got the error that The system cannot find the file specified
file:/C:/Users/phyllis/Documents/old/booklist1.xml
Michael Kay mentioned that we can convert the file name to URI and use doc() or document() to load it. I build the filename URI exactly the same way that I got from document-uri(). What am I wrong here?
The converted file URI looks like this:
<compareWithPath>file:/C:/Users/phyllis/Documents/old/booklist1.xml</compareWithPath>
Returns false when check above file URI using:
<fileExist><xsl:value-of select="doc-available($compareWithPath)"/></fileExist>

The below xsl code works well for my problem:
<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:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:key name="book" match="book" composite="yes" use="*"/>
<xsl:template match="books">
<xsl:param name="compareWith"/>
<xsl:copy>
<xsl:copy-of
select="book[not(key('book', *, document($compareWith)))]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:copy>
<xsl:iterate select="uri-collection('new') ! doc(.)">
<xsl:variable name="fileUri" select=" concat('update/', tokenize( document-uri(.),'/')[last()])"/>
<xsl:result-document method="xml" href="{$fileUri}">
<xsl:apply-templates select="books">
<xsl:with-param name="compareWith" select="concat('old/', tokenize( document-uri(.),'/')[last()])"/>
</xsl:apply-templates>
</xsl:result-document>
</xsl:iterate>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Only a key() is able to eliminate the duplicates, find diff, compare file, etc. Never thought it could be so easy to solve this kind of problem using xsl but once and once xsl proved his power when it comes to xml.
<xsl:iterate select="uri-collection() ! doc(.)">...</xsl:iterate> iterate through uri-collection() makes it easy to loop through the folders.

Related

Coying an entire xml in a Variable using xslt

How can i copy an entire xml as is in an Variable?
Below is the sample xml:
<?xml version="1.0" encoding="UTF-8"?>
<products author="Jesper">
<product id="p1">
<name>Delta</name>
<price>800</price>
<stock>4</stock>
</product>
</products>
I have tried below xslt but it is not working.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:variable name="reqMsg">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:variable>
<xsl:copy-of select="$reqMsg"/>
</xsl:template>
</xsl:stylesheet>
Regards,
Rahul
Your transformation fails because at a certain point, it tries to create a variable (result tree fragment) containing an attribute node. This is not allowed.
It's not really clear what you mean by "copying an entire XML to a variable". But you probably want to simply use the select attribute on the root node:
<xsl:variable name="reqMsg" select="/"/>
This will actually create variable with a node-set containing the root node of the document. Using this variable with xsl:copy-of will output the whole document.
<xsl:copy-of select="document('path/to/file.xml')" />
Or if you need it more than once, to avoid repeating the doc name:
<xsl:variable name="filepath" select="'path/to/file.xml'" />
…
<xsl:copy-of select="document($filepath)" />
The result of document() should be cached IIRC, so don't worry about calling it repeatedly.

remove elements based on external file

I have an external setting file which has some nodes holiding attribute values of main xml document. I need to remove certian nodes from mian xml file if the attribute value is there in the setting file.
My setting file looks like this:
setting.xml
<xml>
<removenode titlename="abc" subtitlename="xyz"></removenode>
<removenode titlename="dvd" subtitlename="dvd"></removenode>
</xml>
Main.xml
<xml>
<title titlename="abc">
<subtitle subtitlename="xyz"></subtitle>
</title>
<title titlename="book">
<subtitle subtitlename="book sub title"></subtitle>
</title>
</xml>
Need a script which look for setting.xml file and remove the title element if titlename and subtitlename found in main.xml. The output should be
output.xml
<xml>
<title titlename="book">
<subtitle subtitlename="book sub title"></subtitle>
</title>
</xml>
I tried using document to read setting.xml file but not able to find how to do the match on main.xml file
<xsl:variable name="SuppressionSettings" select="document('Setting.xml')" />
<xsl:variable name="SuppressSetting" select="$SuppressionSettings/xml/removenode" />
.
Any hint how to implement it?
The key is to use an identity/copy pattern and, before each output, check the current (context) node isn't prohibited by the suppression rules nodeset.
<!-- get suppression settings -->
<xsl:variable name='suppression_settings' select="document('http://www.mitya.co.uk/xmlp/settings.xml')/xml/removenode" />
<!-- begin identity/copy -->
<xsl:template match="node()|#*">
<xsl:if test='not($suppression_settings[#titlename = current()/#titlename and #subtitlename = current()/subtitle/#subtitlename])'>
<xsl:copy>
<xsl:apply-templates select='node()|#*' />
</xsl:copy>
</xsl:if>
</xsl:template>
You can run it here (see output source - the 'abc' title node is omitted):
http://www.xmlplayground.com/9oCYKp
This XSLT indicated below works for the given document.
Note that I'm storing the contents of Setting.xml in a variable as you did, however, I'd then use that variable directly in my queries.
An important issue here is that in the match element of a template, variables cannot be used. Therefore, my template matches any <title> elements and then determines in an <xsl:choose> element whether the attributes match any values given in the settings file - if so, the <title> element will be omitted in the output.
As an explanation for why that test attribute in the <xsl:when> does what it should, imagine a comparison of someAttribute = someOtherAttribute not as a restriction that the attribute someAttribute must have the same value as the attribute someOtherAttribute, but rather as the condition that there must be any two attributes someAttribute and someOtherAttribute with the same value.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="SuppressionSettings" select="document('Setting.xml')" />
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//title">
<xsl:choose>
<xsl:when test="(#titlename = $SuppressionSettings/xml/removenode/#titlename) and (subtitle/#subtitlename = $SuppressionSettings/xml/removenode/#subtitlename)"/>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Here's a more generic answer where the names of the attributes are not hard coded into the XSLT. Like O. R. Mapper pointed out, in XSLT 1.0 you can't use variable references in the match, so I put the document() directly in the predicate. This may not be as efficient as using a variable and then testing the variable.
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[#* = document('setting.xml')/*/removenode/#*]"/>
</xsl:stylesheet>
XML Output (using your 2 xml files with main.xml as the input)
<xml>
<title titlename="book">
<subtitle subtitlename="book sub title"/>
</title>
</xml>

XSLT: Using variables in a key function

I have a following XML file:
<titles>
<book title="XML Today" author="David Perry"/>
<book title="XML and Microsoft" author="David Perry"/>
<book title="XML Productivity" author="Jim Kim"/>
<book title="XSLT 1.0" author="Albert Jones"/>
<book title="XSLT 2.0" author="Albert Jones"/>
<book title="XSLT Manual" author="Jane Doe"/>
</titles>
I want to eliminate some elements and apply the following XSLT:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="author1-search" match="book[starts-with(#author, 'David')]" use="#title"/>
<xsl:template match="book [key('author1-search', #title)]" />
<xsl:key name="author2-search" match="book[starts-with(#author, 'Jim')]" use="#title"/>
<xsl:template match="book [key('author2-search', #title)]" />
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
</xsl:stylesheet>
Is it possible to use an inline xsl variable
<xsl:variable name="Author">
<name>David</name>
<name>Jim</name>
</xsl:variable>
instead of "author1-search", "author2-search", and so on to loop through names?
I can use only XSLT 1.0 (2.0 is currently not supported).
Thanks in advance,
Leo
No, patterns (in XSLT 1.0) cannot contain variable/parameter references.
One way to perform such a task would be like this:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:param name="pAuthor" select="'David Perry'"/>
<xsl:key name="kBookaByAuthor" match="book"
use="#author"/>
<xsl:template match="/">
Books written by <xsl:value-of select="$pAuthor"/> :<xsl:text/>
<xsl:apply-templates
select="key('kBookaByAuthor', $pAuthor)"/>
</xsl:template>
<xsl:template match="book">
<!-- One can do more formatting here -->
<xsl:text>
</xsl:text>
<xsl:value-of select="#title"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<titles>
<book title="XML Today" author="David Perry"/>
<book title="XML and Microsoft" author="David Perry"/>
<book title="XML Productivity" author="Jim Kim"/>
<book title="XSLT 1.0" author="Albert Jones"/>
<book title="XSLT 2.0" author="Albert Jones"/>
<book title="XSLT Manual" author="Jane Doe"/>
</titles>
the wanted, correct result is produced:
Books written by David Perry :
XML Today
XML and Microsoft
Update: In a comment the OP has clarified that:
"I thought I fully specified my requirements in the initial question.
As I mentioned in my question and in my first comment, it would be
helpful to me to see the approach for dealing with more than one
author"
Here is a solution that truly uses keys (note that the "key" in the answer by #Flynn1179 doesn't build any index and is just a constant sequence of strings-- so the function key() using that xsl:key is actually finding a string in a list of strings -- which is O(N) as contrasted to, typically, O(1) for searching in a true index):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common">
<xsl:output method="text"/>
<xsl:param name="pAuthors">
<x>David Perry</x>
<x>Jane Doe</x>
</xsl:param>
<xsl:variable name="vParams" select=
"ext:node-set($pAuthors)/*"/>
<xsl:key name="kBookByAuthor" match="book"
use="#author"/>
<xsl:template match="/">
Books written by : <xsl:text/>
<xsl:apply-templates select="$vParams"/>
<xsl:apply-templates select=
"key('kBookByAuthor', $vParams)"/>
</xsl:template>
<xsl:template match="book">
<!-- One can do more formatting here -->
<xsl:text>
</xsl:text>
<xsl:value-of select="concat('"', #title, '"')"/>
</xsl:template>
<xsl:template match="x">
<xsl:if test="not(position() = 1)">, </xsl:if>
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied to the provided XML document (above), the wanted, correct result is produced:
Books written by : David Perry, Jane Doe
"XML Today"
"XML and Microsoft"
"XSLT Manual"
Do note: In this solution the Exslt function node-set() is used. This is done only for convenience here. In a real usage, the value of the parameter will be specified externally and then the ext:node-set() function isn't necessary.
Efficiency: This solution uses the true power of keys in XSLT. An experiment made using MSXML (3, 4 and 6) XSLT processors shows that if we search for 10000 authors the transformation time with different XSLT processors ranges from: 32ms to 45ms.
Interestingly, the solution presented by #Flynn1179 doesn't indeed make key index and with many XSLT processors it takes (for the same number (10000) of authors) from 1044ms to 5564ms:
MSXML3: 5564 ms.,
MSXML4: 2526ms,
MSXML6: 4867 ms,
AltovaXML: 1044ms.
This is quite inferior to the performance one gets with true key indexing (32ms to 45ms).
Patterns in XSLT 1.0 are not allowed to contain variable or parameter references so you couldn't use variable or parameter references in those key definitions or in the template match attributes you have.
Rather than using variables, you could just include an element in your XSLT sheet in it's own namespace, and refer to that, like this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="my:my">
<xsl:key name="authors" use="document('')/*/my:authors/my:name" match="/" />
<my:authors>
<my:name>David Perry</my:name>
<my:name>Jim Kim</my:name>
</my:authors>
<xsl:template match="book[not(key('authors',#author))]" />
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
The book template matches those that do NOT have a corresponding my:name element for their author, and outputs nothing. The identity template outputs everything else, including the book elements you DO care about. The key's a bit of a hack, it essentially matches the whole document where the name exists, rather than matching the my:name element that matches. Since you only care about it's existence, this shouldn't be a problem.
Alternatively, if you'd rather be able to pass in a list of authors, you can use this:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="authors" select="'David Perry,Jim Kim'" />
<xsl:template match="book">
<xsl:if test="contains(concat(',',$authors,','),concat(',',#author,','))">
<xsl:call-template name="identity" />
</xsl:if>
</xsl:template>
<xsl:template match="#* | node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
The variable's used in an <xsl:if> rather than in the template match, but it does the same job. This particular code needs the list of authors specified as a comma separated list, but it should be easy enough to adapt it if you'd rather use a different format.

Adding multiple namespaces to a xml file

I have a xml file and namespaces are given in the xml file. What I need to do is to use the namespaces given in the xml file only and qualify the xml file. Below is the sample xml file.
<Ticketing xmlns="ticketing.4.0" mfAction="BOOKING">
<Reference>
<Code>190</Code>
</Reference>
<BookingID>194283532</BookingID>
<BookingCode>MCHOI190</BookingCode>
<BookingDate>2011-04-21T15:40:04.000</BookingDate>
<Persons>
<Person>
<Code>ADULT</Code>
<Count>2</Count>
</Person>
<Person>
<Code>CHILD</Code>
<Count>2</Count>
</Person>
</Persons>
<CreditCards>
<CreditCard BookingType="BOOKING">
<BookCreditCard xmlns="creditcard.3.0">
<CardCode>VS</CardCode>
<CardNumber>4444333322221111</CardNumber>
<CardExpire>2011-12-31</CardExpire>
</BookCreditCard>
</CreditCard>
</CreditCards>
</Ticketing>
I have to use the namespaces already present in the xml file and give them a prefix and qualify the xml with those namespaces. The output should be like below:-
<ticket:Ticketing xmlns:ticket="ticketing.4.0" mfAction="BOOKING">
<ticket:Reference>
<ticket:Code>190</ticket:Code>
</ticket:Reference>
<ticket:BookingID>194283532</ticket:BookingID>
<ticket:BookingCode>MCHOI190</ticket:BookingCode>
<ticket:BookingDate>2011-04-21T15:40:04.000</ticket:BookingDate>
<ticket:Persons>
<ticket:Person>
<ticket:Code>ADULT</ticket:Code>
<ticket:Count>2</ticket:Count>
</ticket:Person>
<ticket:Person>
<ticket:Code>CHILD</ticket:Code>
<ticket:Count>2</ticket:Count>
</ticket:Person>
</ticket:Persons>
<ticket:CreditCards>
<ticket:CreditCard BookingType="BOOKING">
<credit:BookCreditCard xmlns:credit="creditcard.3.0">
<credit:CardCode>VS</credit:CardCode>
<credit:CardNumber>4444333322221111</credit:CardNumber>
<credit:CardExpire>2011-12-31</credit:CardExpire>
</credit:BookCreditCard>
</ticket:CreditCard>
</ticket:CreditCards>
</ticket:Ticketing>
Can someone suggest how to implement this.
Thanks
Rudra
I'm not sure is the best way to do it. But it does the job:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="*">
<xsl:element name="ticket:{name()}" namespace="ticketing.4.0">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
<xsl:template match="BookCreditCard|BookCreditCard//*"">
<xsl:element name="credit:{name()}" namespace="creditcard.3.0">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
In XSLT 1.0 there is no guaranteed solution, because implementations are free to use any prefix in the output file that they want. However most processors do the reasonable thing, and #empo's solution will therefore usually work. In XSLT 2.0 it is guaranteed to work.
I would be inclined to use the namespace to control which template is chosen, something like this:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ticket="ticketing.4.0" xmlns:credit="creaditcard.3.0">
<xsl:output indent="yes"/>
<xsl:template match="ticket:*">
<xsl:element name="ticket:{local-name()}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
<xsl:template match="credit:*">
<xsl:element name="credit:{local-name()}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
A more general solution (no hardcoded prefixes and can work with any number of namespaces):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="*">
<xsl:element name=
"{substring(namespace-uri(),1,6)}:{local-name()}"
namespace="{namespace-uri()}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<Ticketing xmlns="ticketing.4.0" mfAction="BOOKING">
<Reference>
<Code>190</Code>
</Reference>
<BookingID>194283532</BookingID>
<BookingCode>MCHOI190</BookingCode>
<BookingDate>2011-04-21T15:40:04.000</BookingDate>
<Persons>
<Person>
<Code>ADULT</Code>
<Count>2</Count>
</Person>
<Person>
<Code>CHILD</Code>
<Count>2</Count>
</Person>
</Persons>
<CreditCards>
<CreditCard BookingType="BOOKING">
<BookCreditCard xmlns="creditcard.3.0">
<CardCode>VS</CardCode>
<CardNumber>4444333322221111</CardNumber>
<CardExpire>2011-12-31</CardExpire>
</BookCreditCard>
</CreditCard>
</CreditCards>
</Ticketing>
the wanted, correct result is produced:
<ticket:Ticketing xmlns:ticket="ticketing.4.0" mfAction="BOOKING">
<ticket:Reference>
<ticket:Code>190</ticket:Code>
</ticket:Reference>
<ticket:BookingID>194283532</ticket:BookingID>
<ticket:BookingCode>MCHOI190</ticket:BookingCode>
<ticket:BookingDate>2011-04-21T15:40:04.000</ticket:BookingDate>
<ticket:Persons>
<ticket:Person>
<ticket:Code>ADULT</ticket:Code>
<ticket:Count>2</ticket:Count>
</ticket:Person>
<ticket:Person>
<ticket:Code>CHILD</ticket:Code>
<ticket:Count>2</ticket:Count>
</ticket:Person>
</ticket:Persons>
<ticket:CreditCards>
<ticket:CreditCard BookingType="BOOKING">
<credit:BookCreditCard xmlns:credit="creditcard.3.0">
<credit:CardCode>VS</credit:CardCode>
<credit:CardNumber>4444333322221111</credit:CardNumber>
<credit:CardExpire>2011-12-31</credit:CardExpire>
</credit:BookCreditCard>
</ticket:CreditCard>
</ticket:CreditCards>
</ticket:Ticketing>
Do note: The first 6 characters of the namespace-uri of each element are used for the prefix of the corresponding generated name. Therefore this solution works correctly as long as the starting 6 characters of any namespace-uri of an element obey the sintactical rules for NCName.

Overriding match="*" template from DocBook XSL

DocBook XSL includes a template that matches all element
<xsl:template match="*">
<xsl:message> .... </xsl:message>
</xsl:template>
I need to override it with another template because my source XML tree contains more that just the DoocBook XML. If I specify such a template in the file it overrides all templates in DocBook XSL. It seems like that all imported templates, are prioritized on the order of import only, and NOT according to how specific the template is.
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:db="http://docbook.org/ns/docbook" version="1.0">
<xsl:import href="docbook-xsl-ns/xhtml/docbook.xsl" />
<xsl:import href="copy.xsl"/>
<xsl:template match="/">
<xsl:apply-templates select="//db:book"/>
</xsl:template>
</xsl:stylesheet>
copy.xsl
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<!-- go process attributes and children -->
<xsl:apply-templates select="#*|node()" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Sample XML source
<?xml version="1.0" encoding="UTF-8"?>
<root>
<http-host>localhost</http-host>
<book xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:svg="http://www.w3.org/2000/svg" xmlns:m="http://www.w3.org/1998/Math/MathML" xml:id="course.528" xml:lang="en" version="5.0">
<info>
<title>Postoperative Complications</title>
</info>
<chapter xml:id="chapter.1">
<title>INTRODUCTION</title>
<para>Postoperative complications are a constant threat to the millions ....</para>
</chapter>
</book>
<errors></errors>
</root>
This is true for both Xalan and xsltproc processors. How do I override this template without having to change the DocBook XSL source. I tried messing with priorities but that did not work.
From what I understand, you want to apply the copy.xsl's template only for non-docbook elements. Try to be more specific in your copy.xsl - by being more specific in your copy.xsl, that template will get selected for all non-docbook elements.
copy.xsl
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform>
<xsl:template match="*[not(namespace-uri() = 'http://docbook.org/ns/docbook')]">
<xsl:element name="{local-name()}">
<!-- go process attributes and children -->
<xsl:apply-templates select="#*|node()" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Depending on the presence of DocBook elements within non-Docbook nodes, you might need to restrict the nodeset for which you apply at the apply-templates part as well(based on the namespace) and maybe mess around the apply-templates flow to make sure it handles it predictably. Hope this is of some use to you..