Using xslt to alter nodes from a copied xml file - xslt

I would like to copy and alter data from another xml data. I have in addition to the normal two input xml files an extra xml file. I would like to embed the entire content of this xml file into my output xml and then change some aspect of it. I have managed to do this by copying the entire file into the right area as desired thus (Thanks to this post here):
<test>
<xsl:copy-of select="document('filename.xml')/*"/>
</test>
Problem is, I want to change some of the data in filename and I don't know how I can get this done. Something along this line, perhaps?
<xsl:template match="document('filename.xml')/root/elemntToBeChanged">
<xsl:apply-templates select="Test/changeItToThis"/>

Try This,
XSLT 2.0:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="#*|node()">
<xsl:copy><xsl:apply-templates select="#*|node()"/></xsl:copy>
</xsl:template>
<xsl:template match="root"><!--Input document's root element -->
<xsl:copy><xsl:apply-templates select="*|document('External-Doc.xml')"/></xsl:copy><!--Extrenal document called here -->
</xsl:template>
</xsl:stylesheet>

Related

Find element that has both children and string in xslt

My source is:
<content>
<caption>text 1</caption>
<element1>Notepad is a basic text-editing program and it's most commonly used to view or edit text files. A text <bold>file</bold> is a <a>file</a> type typically identified by the .txt file name extension.</element1>
<section1>
<element2>Notepad is a basic text-editing program and it's most commonly used to view or edit text files. A text file is a file type typically identified by the .txt file name extension.</element2>
</section1>
</content>
I am trying to extract and create unique ID for the elements (it may be any element) which has both child (character elements) and text, and also the elements which has only text. The <bold> and <a> elements should not be seperated.
<caption id="id1">Text 1</caption>
<element1 id="id2">Notepad is a basic text-editing program and it's most commonly used to view or edit text files. A text <bold>file</bold> is a <a>file</a> type typically identified by the .txt file name extension.</element1>
<element2 id="id3">Notepad....</element2>
Any idea would be greatly appreciated...
I am not quite sure whether you want to preserve the hierarchy or whether you want to output a flat list of those elements you have described; the following simply extracts the described elements as a flat list (though preserving their content), the ids are generated by the XSLT processor:
<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:strip-space elements="*"/>
<xsl:template match="*[not(*) and text()[normalize-space()]] | *[* and text()[normalize-space()]]">
<xsl:copy>
<xsl:attribute name="id" select="generate-id()"/>
<xsl:apply-templates select="#* , node()" mode="copy"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*" mode="copy">
<xsl:copy>
<xsl:apply-templates select="#* , node()" mode="#current"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When applied to your input sample, Saxon 9 outputs
<?xml version="1.0" encoding="UTF-8"?>
<caption id="d1e2">text 1</caption>
<element1 id="d1e4">Notepad is a basic text-editing program and it's most commonly used to view or edit text files. A text <bold>file</bold> is a <a>file</a> type typically identified by the .txt file name extension.</element1>
<element2 id="d1e13">Notepad is a basic text-editing program and it's most commonly used to view or edit text files. A text file is a file type typically identified by the .txt file name extension.</element2>

Problems with XSLT and apply templates

I'm going to be brief. I'm doing XSLT on the client. The output is a report/html with data. The report consists of several blocks, ie one block is one child element of root-node in the xml file.
There are n reports residing in n different xslt-files in my project and the reports can have the same block. That means if there is a problem with one block for one report and it is in n reports i have to update every n report (xslt file).
So i want to put all my blocks in templates (kind-of-a businesslayer) that i can reuse for my reports by xsl:include on the templates for those reports.
So the pseudo is something like this:
<?xml version="1.0".....?>
<xsl:stylesheet version="1.0"....>
<xsl:include href="../../Blocks/MyBlock.xslt"/>
<xsl:template match='/'>
<xsl:apply-templates />
</xsl:template>
</xsl:stylesheet>
MyBlock.xslt:
<?xml version="1.0"....?>
<xsl:stylesheet version="1.0".....>
<xsl:template match='/root/rating'>
HTML OUTPUT
</xsl:template>
</xsl:stylesheet>
I hope someone out there understands my question. I need pointers on how to go about this, if this is one way to do it. But it doesn't seem to work.
Below is my experience that how am dealing this.
This is example which I modified your code.
<?xml version="1.0"?>
<xsl:stylesheet version="1.0">
<xsl:include href="../../Blocks/MyBlock.xslt"/>
<xsl:template match="/">
<xsl:apply-templates select="node()" mode="callingNode1"/>
</xsl:template>
</xsl:stylesheet>
MyBlock.xslt:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0">
<xsl:template mode="callingNode1" match="*">
HTML OUTPUT
</xsl:template>
<xsl:template mode="callingNode2" match="/root/rating">
HTML OUTPUT
</xsl:template>
</xsl:stylesheet>
Here am calling the nodes based on the mode & match.

How to copy all child nodes of any type of a template context element

I am transforming XML into HTML using XSLT.
I have the following XML structure:
<root>
<element>
<subelement>
This is some html text which should be <span class="highlight">displayed highlighted</span>.
</subelement>
</element>
</root>
I use the following template for the transformation:
<xsl:template name="subelement">
<xsl:value-of select="." />
</xsl:template>
Unfortunately, I lose the <span>-tags.
Is there a way to keep them so the HTML is displayed correctly (highlighted)?
The correct way to get the all the contents of the current matching node (text nodes included) is:
<xsl:template match="subelement">
<xsl:copy-of select="node()"/>
</xsl:template>
This will copy everything descendent.
Try using <xsl:copy-of... instead of <xsl:value-of... for example:
<xsl:template name="subelement">
<xsl:copy-of select="*" />
</xsl:template>
Note the * which will stop the <subelement></subelement> bits being output to the results, rather than using . which will include the <subelement></subelement> bits .
For example, the xsl stylesheet:
<?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="2.0">
<xsl:template match="root/element">
<output>
<xsl:apply-templates select="subelement"/>
</output>
</xsl:template>
<xsl:template match="subelement">
<xsl:copy-of select="*"/>
</xsl:template>
</xsl:stylesheet>
when applied to your example xml file returns:
<?xml version="1.0" encoding="UTF-8"?>
<output>
<span class="highlight">displayed highlighted</span>
</output>
The <xsl:value-of> declaration takes the concatenated contents of all text nodes within the element, in sequential order, and doesn't output any elements at all.
I'd recommend using <xsl:apply-templates> instead. Where it finds a text node, it will output the contents as-is, but you would need to define a template for handling span tags to convert them to html ones. If that span tag IS an html tag, then strictly speaking, you should have separate namespaces for your own document structure and html.

Can xslt read or skip <beans:beans> tag?

I'm creating an XSLT file for XML which contains a tag <beans:bean>, probably from spring framework. Basically, the structure of the XML is as follows:
<beans:beans>
<fix>
<message>
important content
</message>
</fix>
</beans:beans>
I can't find a way to get rid of the <beans:beans> tag, actually the relevant content for me is under the message tag.
Using <xsl:for-each select="fix/message"> I am able to reach the content I need. However I have to remove the <beans:beans> tag manually
Is there a way to make XSLT skip or read the <beans:beans> tag?
This is idiomatically solved using the identity transform with an override:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:beans="http://someuri">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="beans:beans">
<xsl:apply-templates />
</xsl:template>
</xsl:stylesheet>
Applied to this input:
<root>
<beans:beans xmlns:beans="http://someuri">
<fix>
<message>
important content
</message>
</fix>
</beans:beans>
</root>
Removes the unwanted element:
<root>
<fix>
<message>
important content
</message>
</fix>
</root>
Some notes:
This copies everything in the file, unchanged, except the beans:beans element
Your beans element has a namespace prefix. I have added a namespace URI to make this transformation work.
Your stylesheet also needs to be aware of the namespace. Notice the use of xmlns:beans="http://someuri". You'll need to modify this to map to the actual beans namespace.

XPath: Selecting nodes included by an <xsl:include>

There's an XSL that includes another XSL:
<xsl:include href="registered.xsl"/>
That included file has a list of nodes:
<g:registered>
<node1/>
<node2/>
</g:registered>
Documentation says that "the children of the <xsl:stylesheet> element in this document replace the element in the including document", so I would think that, given the include directive has worked, I can select g:registered nodes like if they always belonged to the inluding document:
select="document('')/xsi:schema/g:registered"
That returns an empty nodeset though.
However, this:
select="document('registered.xsl')/xsi:schema/g:registered"
does select what is required, but that, as I suppose, means opening the included file for the second time which doesn't seem nice to me.
So how do I select those includes without opening the file second time?
EDIT
Requested document structure:
Included document:
<?xml version='1.0' encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:g="http://www.sample.com/ns">
<g:registered-templates>
<SampleTemplate/>
<WrongTemplate/>
</g:registered-templates>
<xsl:include href="Sample Template.xsl" />
<xsl:include href="Wrong Template.xsl" />
</xsl:stylesheet>
Including document:
<?xml version='1.0' encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:g="http://www.sample.com/ns">
<xsl:output method="text"/>
<xsl:include href="Label Registration.xsl"/>
<!-- How do I refer to just loaded inclusion without directing engine to the file again? -->
<xsl:variable name="template-names" select="document('Label Registration.xsl')/xsl:stylesheet/g:registered-templates"/>
<xsl:template match="Job">
<xsl:for-each select="WorkItem">
<xsl:apply-templates select="$template-names/*[local-name()=current()/#name]">
<xsl:with-param name="context" select="." />
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Selecting into your variable template-names queries the transformation source document - not your included stylesheet.
If you want to refer to g:registered-templates you have to point to the file like a second source document.
EDIT
I'm not really sure. but it looks like you want to create an element according to the attribute value.
In that case this post will be interesting for you.
<xsl:for-each select="WorkItem">
<xsl:element name="{Type}" >
<xsl:value-of select="current()/#name"/>
</xsl:element>
</xsl:for-each>
Ok, my understanding was wrong.
The document('') function opens the file anyway, so it has no advantages, performance-wise, over document('registered.xsl'). And since it queries the file, not the now-modified DOM model of current document, the result does not include my includes.
And it is not possible to query DOM model of the transformation template itself, as far as I'm concerned.