How to put 'and' condition to remove an xml element from an xslt - xslt-1.0

I am new to XSLT and got a condition to remove an element from XML file on the basis of condition applied in XSLT. I have to remove en element on the basis of 2 conditions on the same attribute.
Here is my dummy code:
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="cdm:attributeList/cdm:attribute[cdm:attributeName = 'format'] and cdm:attributeList/cdm:attribute[cdm:attributeValue = 'XYZ']" />
while running the XSLT file I get the following error:
1. Extra illegal tokens: 'and'
2. "exclude-result-prefixes" attribute is not allowed on the xsl:output element!
Could someone please help me out in this?
Thanks.

The template matching condition is incorrect, and operator is not allowed when matching template. You need to modify the template matching condition as below which corresponds to the combination of the required conditions.
<xsl:template match="cdm:attributeList/cdm:attribute[cdm:attributeName = 'format'][cdm:attributeValue = 'XYZ']" />
For the second issue of exclude-result-prefixes, it is an attribute of <xsl:stylesheet> and not <xsl:output>. So if you do not want the output nodes to have the cdm prefix, modify the <xsl:stylesheet> as below
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:cdm="http://someurl" exclude-result-prefixes="cdm">

Related

How to preserve attributes in xsl:variable body? [duplicate]

This question already has an answer here:
Setting a variable conditionally with no cut of ancestor axis
(1 answer)
Closed 5 months ago.
data
<mydoc>
<setting>foo</setting>
<foo sound="aaaa"/>
<bar sound="brrr"/>
<cat sound="meow"/>
</mydoc>
if no conditional logic is needed,
<xsl:variable name="result1" select="/mydoc/foo"/>
works fine.
but if I need conditional logic,
<xsl:variable name="result2">
<xsl:choose>
<xsl:when test="/setting='foo'">
<!-- what to put here -->
</xsl:when>
<xsl:when test="/setting='cat'">
<!-- what to put here -->
</xsl:when>
<xsl:otherwise>
<!-- what to put here -->
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
desired output:
when setting = 'foo', result = <foo sound="aaa"/> (the whole element complete with attribute)
when setting = 'cat', result = <cat sound="meow"/> (the whole element complete with attribute)
otherwise, result = <bar sound="brrr"/> (the whole element complete with attribute)
How do I get the result2 variable to be an element with attributes, as it does in result1? I want to use $result2/sound, and some other elements / attributes of $result2 and / or it's children.
<xsl:variable name="result2" select="/mydoc[setting='foo']/foo |
/mydoc[setting='cat']/cat |
/mydoc[not(setting='foo' or setting='cat')]/bar"/>
Because of the conditions in square brackets exactly one member of the union will effectively be selected.
If you put something inside the <xsl:variable> element rather than use select, your variable will contain a result tree fragment, not a nodeset.
If you insist on using xsl:choose (why?) then the only option open to you is to use xsl:copy. However, this has some side effects:
This will create a copy of the selected node/s and make it a child of the variable; in effect, it will create a separate document and the copied nodes will no longer be descendants of the XML input's root;
The variable will be a result-tree-fragment and you won't be able to process it in any way unless you convert it to a node-set first. Here, "process" includes accessing individual nodes inside the variable.
The following example demonstrates this:
XML
<mydoc>
<setting>foo</setting>
<foo bar="a"/>
<bar foo="b"/>
</mydoc>
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/mydoc">
<xsl:variable name="temp">
<xsl:choose>
<xsl:when test="setting='foo'">
<xsl:copy-of select="foo"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="bar"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<output>
<xsl:value-of select="exsl:node-set($temp)/foo/#bar" />
</output>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<output>a</output>
Do note that if you change:
<xsl:value-of select="exsl:node-set($temp)/foo/#bar" />
to:
<xsl:value-of select="$temp/foo/#bar" />
you will get an error.

Concatenate to existing value in xlst

With XSLT 1.0 I simply want to add a negative sign before the value in the Identifier element. The stylesheet I have shown below returns the same (i.e. the first instance) Identifier value for each instance of RToP. There can be more than one RToP. PLease advise how to modify the match so I return the desired output below. Thanks. I'm omitting the namespace in the xml below.
<TRAN><DE><REF>
<RToP><Identifier>100</Identifier>
</RToP>
<RToP><Identifier>150</Identifier>
</RToP>
</TRAN></DE></REF>
Existing output
<TRAN><DE><REF>
<RToP><Identifier>-100</Identifier>
</RToP>
<RToP><Identifier>-100</Identifier>
</RToP>
</TRAN></DE></REF>
Desired output
<TRAN><DE><REF>
<RToP><Identifier>-100</Identifier>
</RToP>
<RToP><Identifier>-150</Identifier>
</RToP>
</TRAN></DE></REF>
Existing stylesheet
<xsl:template match="//my:TRAN/my:DE/my:REF/my:RToP/my:Identifier[position()]">
<my:Identifier>
<xsl:value-of select="concat('-', //my:TRAN/my:DE/my:REF/my:RToP/my:Identifier[position()])"/>
</my:Identifier>
</xsl:template>
For this type of transformation you need to be use relative path instead of absolute path.
first you have to create at identical transformation to retain its structure.
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
than you have to define Identifier as template that run only on Identifier and there is no need to use predicates for that.
<xsl:template match="Identifier">
<Identifier>
<xsl:value-of select="concat('-', .)"/>
</Identifier>
</xsl:template>

BizTalk Mapping Single and Multiple elements

I am trying to transform via the map a single birth name node and multiple surname nodes into a repeating other surname nodes. I'm running into some difficulties that when the birth name node is not present then multiple surname nodes fail to be written.
I've attempted multiple implementations around functoids and xslt call template neither appear to be working, as soon as the birth name is missing no surname elements are output.
Can this be done in functoids from the map ? or does this have to be done via a xslt call template?
Schema Input
<root>
<Subject>
<birthname>
<name>Birthname</name>
</birthname>
<multiplesurname>
<name>surname</name>
</multiplesurname>
<multiplesurname>
<name>surname2</name>
</multiplesurname>
<multiplesurname>
<name>surname3</name>
</multiplesurname>
</Subject>
<Mother></Mother>
<Farther></Farther>
<Other></Other>
</root>
Schema Output
<root>
<persona>
<Othername>Birthname</Othername>
<Othername>surname</Othername>
<Othername>surname2</Othername>
<Othername>surname3</Othername>
</persona>
<personb></personb>
</root>
I think your problems may be caused by having a name node and then an descendant node also named name. This might be causing an infinite loop for you. Here is some XSLT code that will get the job done for you.
<xsl:template match="name">
<xsl:copy>
<xsl:apply-templates select=".//name" mode="secondName"/>
</xsl:copy>
</xsl:template>
<xsl:template match="name" mode="secondName">
<xsl:element name="Othername">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<!-- Identity. -->
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
You could probably do this with a table looper, but a XSLT call template for it shouldn't be too bad - something like this should work for you:
<xsl:template name="nameFlattener">
<xsl:param name="birthname"/>
<xsl:element name="Othername">
<xsl:value-of select="$birthname"/>
</xsl:element>
<xsl:for-each select="//multiplesurname">
<xsl:element name="Othername">
<xsl:value-of select="name"/>
</xsl:element>
</xsl:for-each>
</xsl:template>
Have your name node from birthname going into that template as the first parameter, and output it to the Othername repeating node on the destination.
After running into further difficulties with XSLT call-template I found that a solution using functoids was possible and achieved using a combination of looping functoids from the birthname and multiplesurname along with straight link from the source node to the destination node.

Looping a variable length array with namespaces in XSLT

My previous question[1] is related to this. I found the answer for that. Now I want to loop a variable length array with namespaces. My array:
<ns:array xmlns:ns="http://www.example.org">
<value>755</value>
<value>5861</value>
<value>4328</value>
<value>2157</value>
<value>1666</value>
</ns:array>
My XSLT code:(have added the namespace in the root)
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns1="http://www.example.org">
<xsl:template match="/">
<xsl:variable name="number" select="ns:array" />
<xsl:for-each select="$number">
<xsl:value-of select="$number" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
[1]https://stackoverflow.com/questions/20287219/looping-a-variable-length-array-in-xslt
IMHO you confused yourself by introducing a variable called number which actually contains a node set of value tags. Then, as a consequence you used your variable as singe item/node which does not yield the desired result (presumingly, since you did not really tell us what you want to do with the values).
Also, I think your question does not really have anything to with namespace issues as such. You just have to make sure that the namespaces in your select expressions match the namespaces in your input file.
I would suggest to do without the variable and change the way you retrieve the current value:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns1="http://www.example.org">
<xsl:template match="/">
<xsl:for-each select="ns:array">
<!-- Inside here you can work with the `value` tag as the _current node_.
There are two most likely ways to do this. -->
<!-- a) Copy the whole tag to the output: -->
<xsl:copy-of select="." />
<!-- or b1) Copy the text part contained in the tag to the output: -->
<xsl:value-of select="." />
<!-- If you want to be on the safe side with respect to white space
you can also use this b2). This would handle the case that your output
is required not to have any white space in it but your imput XML has
some. -->
<xsl:value-of select="normalize-space(.)" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Can disable-output-escaping be set using a template parameter?

Why won't the following work in XSLT1.0?
<xsl:template name="GenerateSummaryOld">
<xsl:param name="Content" />
<xsl:param name="Length" />
<xsl:param name="DisableOutputEscaping" />
<xsl:value-of select="substring($Content, 1, $Length)" disable-output-escaping="$DisableOutputEscaping" />
<xsl:if test="string-length($Content) > $Length"><i>...text has been shortened</i></xsl:if>
</xsl:template>
I'm using the following when calling the template:
<xsl:with-param name="DisableOutputEscaping">no</xsl:with-param>
I'm trying this in a SharePoint Content Query WebPart but I get a web part error. If I hard-code disable-output-escaping as "yes" or "no" in the template, i get no error.
Short answer: the value of disable-output-escaping must be specified literally in the XSLT stylesheet; it cannot be calculated at stylesheet execution time.
That is, the behavior you are observing is the behavior prescribed by the language definition.
Longer answer: The XSLT 1.0 spec shows the syntax of xsl:value-of like this (more or less):
<!-- Category: instruction -->
<xsl:value-of
select = string-expression
disable-output-escaping = "yes" | "no" />
Note that "string-expression" is italicized here; it means that the select attribute has as its value not the string "string-expression" but any XPath expression which can be evaluated and coerced to a string. But the "yes" and "no" of disable-output-escaping are not italicized, not described as being an expression, and not described as being an attribute-value template. The "yes" or "no" value must be given literally.
The closest the spec comes to saying this explicitly (that I could find) is the note in section 7.6.2 on attribute value templates:
NOTE:Not all attributes are interpreted as attribute value templates. Attributes whose value is an expression or pattern, attributes of top-level elements and attributes that refer to named XSLT objects are not interpreted as attribute value templates. ...
This is one of a number of early-binding constraints in XSLT designed to ensure that stylesheets could be compiled and not just interpreted.
The explanation was provided in the good answer by C. M. Sperberg-McQueen.
Here is a workaround:
<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="vAmp">&</xsl:variable>
<xsl:variable name="vYesNo" select="'yes'"/>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="$vYesNo = 'yes'">
<xsl:value-of select="$vAmp" disable-output-escaping="yes"/>
</xsl:when>
<xsl:when test="$vYesNo = 'no'">
<xsl:value-of select="$vAmp" disable-output-escaping="no"/>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on any XML document (not used), the result is:
&
If we replace:
<xsl:variable name="vYesNo" select="'yes'"/>
with:
<xsl:variable name="vYesNo" select="'no'"/>
the result of the modified transformation now is:
&