template match - how to specify OR conditon - xslt

I want to specify a match expression in a template that will get invoked on multiole namespaces of element:
<xsl:template match="*[namespace-uri()='abc.com' or namespace-uri()='def.com']">
...
</xsl:template>
But this does not seem to work. It only gets invoked if left side of or expression is true.

The usual approach to work with namespaces is to declare them e.g.
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:abc="http://example.com/abc"
xmlns:def="http://example.com/def"
exclude-result-prefixes="abc def">
<xsl:template match="abc:* | def:*">...</xsl:template>
...
</xsl:stylesheet>
That being said, I don't see anything wrong with your or predicate expression, other than that you haven't provided any input you use it with.

<xsl:template match="*[namespace-uri()='abc.com' or namespace-uri()='def.com']">
...
</xsl:template>
But this does not seem to work.
This is correct code.
So, the problem is in the code that you haven't shown to us. Please, also provide a simple XML document so that everyone could apply the provided XSLT code to the provided XML document and repro the problem.
Here is a demonstration that the "suspected" code is correct:
<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="*[namespace-uri()='def.com' or namespace-uri()='abc.com']">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on this XML document:
<a>
<b:b xmlns:b="abc.com">
<c/>
</b:b>
<f/>
<d:d xmlns:d="def.com">
<e/>
</d:d>
</a>
the wanted, correct result is produced:
<b:b xmlns:b="abc.com">
<c/>
</b:b>
<d:d xmlns:d="def.com">
<e/>
</d:d>

Related

Replace xsi:nil=“true” with open and close tags

I need to do the following transformation in order to get a message pass through a integration broker which does not understand xsi:nil=“true”. I know that for strings having some thing like <abc></abc> is not same as <abc xsi:nil=“true”/> but I have no option.
My input XML:
<PART>
<LENGTH_UOM xsi:nil="1"/>
<WIDTH xsi:nil="1"/>
</PART>
Expected outcome:
<PART>
<LENGTH_UOM><LENGTH_UOM>
<WIDTH></WIDTH>
</PART>
Please let me know your suggestions.
To remove all xsi:nil attributes combine the identity template with an empty template matching xsi:nil.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://xsi.com">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="node()|#*"> <!-- identity template -->
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
</xsl:template>
<xsl:template match="#xsi:nil" /> <!-- empty template -->
</xsl:stylesheet>
If you only want to remove those whose value is true use the following empty template instead.
<xsl:template match="#xsi:nil[.='1' or .='true']" />
Concerning the opening and closing tag topic I suggest reading this SO question in which Martin Honnen states that (in the comments of the answer):
I am afraid whether an empty element is marked up as or or is not something that matters with XML and is usually not something you can control with XSLT processors.

XSLT why is this not selecting what I want but selecting the entire xml?

I am trying to make a simple selection just for a test, but it doesn't seem to work.
Here is the sml: http://pastebin.com/cwEcVEiL
And here is my xslt style:
<?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:tei="http://www.tei-c.org/ns/1.0"
exclude-result-prefixes="xs"
version="2.0">
<xsl:template match="/tei:TEI/tei:text/tei:body">
TEST
</xsl:template>
</xsl:stylesheet>
With this style it just selects the entire xml document
but if I type match="/", then I outputs TEST once, as expected.
What is the problem?
For elements which aren't matched by any template at all, XSLT will apply built in default templates.
Unless you want this default behaviour, you should override these, e.g. :
<xsl:template match="/">
<xsl:apply-templates select="/tei:TEI/tei:text/tei:body" />
</xsl:template>
<xsl:template match="tei:body">
TEST
</xsl:template>

Can I check condition in template match in XSLT?

I want to check variable in template match, is it possible?
like:
<xsl:template match="*:Item and $MODE='PURCHASE'">
So template should check variable $MODE='PURCHASE' as well
Not in XSLT 1.0.
In XSLT 2.0 one can have variable references -- in the predicates of the template match pattern.
For example:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="MODE" select="'PURCHASE'"/>
<xsl:template match="*:Item[$MODE='PURCHASE']">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on this XML document:
<t xmlns:x="some:x">
<x:Item>someText</x:Item>
</t>
the wanted, correct result is produced:
someText

Preserving priority of operands in one-liner Xpath 1.0

I can't really formulate it properly, better with example.
XML:
<?xml version="1.0" encoding="UTF-8"?>
<foo>
<bar id="someId" class="someClass"/>
<buz class="someClass" id="someId"/>
<ololo class="someClass"/>
<test id="someId"/>
</foo>
XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*/*">
<xsl:value-of select="#id | #class"/><xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
The result:
someId
someClass
someClass
someId
What I need
I need that "priority" of attributes remained as stated in my xpath expression.
So, if we call #id | #class an expression with two operands, I need that the attributes would be taken not in a document order, but in the order of how two operands were specified in the expression.
So, the result should be:
someId
someId
someClass
someId
#class should be taken only if #id is not present.
I know, that it can be done with conditional logic, but I'm really interested in a short solution, because it's common and used as attribute value template.
It might be obvious and I am missing The Elegant One.
Do note that I'm speaking in terms of XPath 1.0.
Use:
#id | #class[not(../#id)]
This XPath expression selects always one node: #id if it exists, and only if #id doesn't exist then #class.
So this transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output method="text"/>
<xsl:template match="foo/*">
<xsl:value-of select="#id | #class[not(../#id)]"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<foo>
<bar id="someId" class="someClass"/>
<buz class="someClass" id="someId"/>
<ololo class="someClass"/>
<test id="someId"/>
</foo>
produces the wanted, correct results:
someId
someId
someClass
someId

xslt apply-templates selects all remaining textnodes

I have this simplified xml:
<?xml version="1.0" encoding="UTF-8"?>
<a>
<b>
<c>
<d>1</d>
<e>2</e>
</c>
</b>
<f>
<g>3</g>
</f>
</a>
This is the xslt i try to apply:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="a">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="b">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="c">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="d">
</xsl:template>
</xsl:stylesheet>
When I apply this sheet, I get output 2 3, which are the remaining textnodes. I've read about the built-in templates which get applied if it can't find a matching template, but in this case, it should find a template?
What is going on?
Edit:
In this case, i would expect to see nothing, because the templates are empty. But i get 2 3 in stead.
When you do <xsl:template match="d">, you tell the processor to ignore all nodes under <d>.
All other nodes are processed with default rules, including the text() one, which is to print the text.
That's why you see 23, and not 1.
Start from the root:
<xsl:template match="/a">
And specify either a mode (so that the default template does not get called, because it does not find a template for e, f and g) or define your own * template which does nothing at the end of the stylesheet:
<xsl:template match="*"/>