XSLT sort when using OR in select - xslt

Is there any way to get this to sort in the order of the select statement when it finds one or more PIDs?
<xsl:apply-templates select="td:Benutzer_zu_POI[
td:PID = '400639' or
td:PID = '400929' or
td:PID = '401184' or
td:PID = '401006' or
td:PID = '430003408' or
td:PID = '401519' or
td:PID = '400660' or
td:PID = '500287' or
td:PID = '200461' or
td:PID = '400756']">
Many thanks for any help!

You can, but it's not as automatic as you may be hoping. It would go something like this:
<xsl:apply-templates select="td:Benutzer_zu_POI[
td:PID = '400639' or
td:PID = '400929' or
td:PID = '401184' or
td:PID = '401006' or
td:PID = '430003408' or
td:PID = '401519' or
td:PID = '400660' or
td:PID = '500287' or
td:PID = '200461' or
td:PID = '400756']">
<xsl:sort select="string-length(
substring-before(
'|400639|400929|401184|401006|...|400756|',
concat('|', td:PID, '|')))"
data-type="number" />
</xsl:apply-templates>
To explain how this works, the intent is to produce smaller numbers as a result of the select, depending on the item's order. So for example, for 400639, this evaluates to:
string-length(
substring-before(
'|400639|400929|401184|401006|...|400756|',
'|400639|'))
string-length('')
0
for 401184, it's
string-length(
substring-before(
'|400639|400929|401184|401006|...|400756|',
'|401184|'))
string-length('|400639|400929')
14
and so on.
The purpose of the concat() is to delimit the value in pipe symbols to prevent partial matches. If we didn't use the concat(), you might have a situation like this:
(assume td:PID = 456)
string-length(
substring-before(
'|123456|234567|34567|456|',
'456'))
string-length(
'|123')
4
meaning that 456 would be placed before 23456 and 34567 when it should actually be after them. When it's surrounded in delimiters, this doesn't happen:
string-length(
substring-before(
'|123456|234567|34567|456|',
'|456|'))
string-length(
'|123456|234567|34567')
20

Would this do the trick?
<xsl:apply-templates select="td:Benutzer_zu_POI[td:PID = '400639']/>
<xsl:apply-templates select="td:Benutzer_zu_POI[td:PID = '401184']/>
<xsl:apply-templates select="td:Benutzer_zu_POI[td:PID = '401006']/>
<xsl:apply-templates select="td:Benutzer_zu_POI[td:PID = '430003408']/>
<xsl:apply-templates select="td:Benutzer_zu_POI[td:PID = '401519']/>
<xsl:apply-templates select="td:Benutzer_zu_POI[td:PID = '400660']/>
<xsl:apply-templates select="td:Benutzer_zu_POI[td:PID = '500287']/>
<xsl:apply-templates select="td:Benutzer_zu_POI[td:PID = '200461']/>
<xsl:apply-templates select="td:Benutzer_zu_POI[td:PID = '400756']/>
(Whether it's equivalent or not depends on the details of your data, which you haven't shown us. Your version will only display each Benutzer once even if it matches several of the PIDs.).

Related

How do I only output a record if and only if all the values are the desired ones using XSLT

I have a large XML file with many request, within each request there may be multiple orders. I want to only output the request if all its orders have a certain status that indicate its been completed.
The Status <Stat> I want are Stat03, Stat04, Stat05 and Stat06.
My XML looks like this:
<?xml version='1.0' encoding='UTF-8'?>
<document>
<BO>
<MainReq>
<UR>
<ReqNum>REQ001.00</ReqNum>
<Description>Description 01</Description>
<PH>
<PN>REQ001.01</PN>
<Stat>Stat05</Stat>
</PH>
<PH>
<PN>REQ001.02</PN>
<Stat>Stat04</Stat>
</PH>
<PH>
<PN>REQ001.03</PN>
<Stat>Stat06</Stat>
</PH>
</UR>
</MainReq>
<MainReq>
<UR>
<ReqNum>REQ002.00</ReqNum>
<Description>Description 02</Description>
<PH>
<PN>REQ002.01</PN>
<Stat>Stat05</Stat>
</PH>
<PH>
<PN>REQ002.02</PN>
<Stat>Stat04</Stat>
</PH>
<PH>
<PN>REQ002.03</PN>
<Stat>Stat03</Stat>
</PH>
<PH>
<PN>REQ002.04</PN>
<Stat>Stat06</Stat>
</PH>
<PH>
<PN>REQ002.05</PN>
<Stat>Stat01</Stat>
</PH>
</UR>
</MainReq>
</BO>
</document>
<MainReq> contains the request and within it there can be multiple orders <PH>
The desire output would be this, since the only request that meets the criteria is REQ001.
REQ002 has one <PH> that is in Stat01 so it does not qualify.
<document>
<BO>
<IfReq>
<ReqNum>REQ001</ReqNum>
<Date>2022-07-21+02:00</Date>
</IfReq>
</BO>
</document>
My solution was to count all the <PH> and then count ONLY the <Stat> that are in any of the these states, Stat03, Stat04, Stat05 and Stat06. Once I have those values I can compare them and if they are equal I output the request number and date. A <MainReq> does not have to have all of those states but I only want to count the <PH> that are in that set of states to compare with the total count of <PH>.
Edit to add more clarity..
My XSL code:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
xmlns:lookup="lookup" xmlns:exsl="http://exslt.org/common" exclude-result-prefixes="lookup exsl">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes" encoding="utf-8" media-type="xml/plain" />
<xsl:strip-space elements="*" />
<xsl:template match="node() | #*">
<xsl:copy>
<xsl:apply-templates select="node() | #*" />
</xsl:copy>
</xsl:template>
<xsl:template match="MainReq">
<xsl:variable name="subTotalCount">
<xsl:value-of select="count(UR/PH/PN)" />
</xsl:variable>
<xsl:variable name="subCompletedCount">
<xsl:choose>
<xsl:when test="UR/PH/Stat = 'Stat03' and 'Stat04' and 'Stat05' and 'Stat06'">
<xsl:value-of select="sum(count(UR/PH/Stat) )" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'0'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<!-- This is the final output -->
<xsl:if test= "$subTotalCount = $subCompletedCount">
<IfReq>
<xsl:copy-of select="UR/ReqNum"/>
<Date>
<xsl:value-of select="current-date()"/>
</Date>
</IfReq>
</xsl:if>
<!-- For debugging -->
<Req>
<xsl:copy-of select="UR/ReqNum"/>
</Req>
<sub>
<TotalCount>
<xsl:value-of select="$subTotalCount"/>
</TotalCount>
<compCount>
<xsl:value-of select="$subCompletedCount"/>
</compCount>
<xsl:copy-of select="UR/PH/PN"/>
</sub>
</xsl:template>
</xsl:stylesheet>
You could use this:
<!-- This is the final output -->
<xsl:if test="count(UR/PH/Stat) = count(UR/PH/Stat[matches(. , 'Stat0[3456]')])">
<IfReq>
<xsl:copy-of select="UR/ReqNum"/>
<Date>
<xsl:value-of select="current-date()"/>
</Date>
</IfReq>
</xsl:if>
It uses count on matches() in the predicate to count the wanted Stat and compares is with total count of Stat
Your explanation is a bit difficult to follow, but I think you are asking for
//MainReq[every $s in .//Stat satisfies $s = ('Stat03', 'Stat04', 'Stat05', 'Stat06')]
Use this one-liner XPath 2.0 expression:
//MainReq[not(.//Stat[not(. = ('Stat03', 'Stat04', 'Stat05', 'Stat06'))])]
XSLT-based verification:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|#*">
<xsl:copy-of select="//MainReq[not(.//Stat[not(. = ('Stat03', 'Stat04', 'Stat05', 'Stat06'))])]"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<document>
<BO>
<MainReq>
<UR>
<ReqNum>REQ001.00</ReqNum>
<Description>Description 01</Description>
<PH>
<PN>REQ001.01</PN>
<Stat>Stat05</Stat>
</PH>
<PH>
<PN>REQ001.02</PN>
<Stat>Stat04</Stat>
</PH>
<PH>
<PN>REQ001.03</PN>
<Stat>Stat06</Stat>
</PH>
</UR>
</MainReq>
<MainReq>
<UR>
<ReqNum>REQ002.00</ReqNum>
<Description>Description 02</Description>
<PH>
<PN>REQ002.01</PN>
<Stat>Stat05</Stat>
</PH>
<PH>
<PN>REQ002.02</PN>
<Stat>Stat04</Stat>
</PH>
<PH>
<PN>REQ002.03</PN>
<Stat>Stat03</Stat>
</PH>
<PH>
<PN>REQ002.04</PN>
<Stat>Stat06</Stat>
</PH>
<PH>
<PN>REQ002.05</PN>
<Stat>Stat01</Stat>
</PH>
</UR>
</MainReq>
</BO>
</document>
The Xpath expression is evaluated, and the result of this evaluation (all selected nodes) is sent to the output:
<MainReq>
<UR>
<ReqNum>REQ001.00</ReqNum>
<Description>Description 01</Description>
<PH>
<PN>REQ001.01</PN>
<Stat>Stat05</Stat>
</PH>
<PH>
<PN>REQ001.02</PN>
<Stat>Stat04</Stat>
</PH>
<PH>
<PN>REQ001.03</PN>
<Stat>Stat06</Stat>
</PH>
</UR>
</MainReq>
Explanation:
For a full explanation, see: https://stackoverflow.com/a/58792165/36305

Get first occurrence of XSLT stylesheet

I have the following code which I use to get the sum of product values.
<xsl:for-each select="//fn:array[#key= 'Items']/fn:map[*[#key = 'OrderId'][.= $OrderId ] and *[#key = 'Type'][.= 'ServiceRevenue' ] ] ">
<amount>
<xsl:value-of select="fn:map[#key ='Amount']/*[#key = 'Net']" />
</amount>
</xsl:for-each>
I am trying to only calculate the first occurrence where [*[#key = 'OrderId'][.= $OrderId ].
I tried the following, but I am still getting all the occurrences:
<xsl:for-each select="//fn:array[#key= 'Items']/fn:map[*[#key = 'OrderId'][.= $OrderId ][0] and *[#key = 'Type'][.= 'ServiceRevenue' ] ] ">
<amount>
<xsl:value-of select="fn:map[#key ='Amount']/*[#key = 'Net']" />
</amount>
</xsl:for-each>
Sample JSON:
[
{
"Items":[
{
"Id":"5b44f410-7034-4972-919d-acac00ead7e9",
"OrderId":"e7791603-ca5f-47c4-9b0c-acac00ead753",
"Type":"ServiceRevenue",
"Amount":{
"Value":25.0,
"Net":25.0,
"Tax":0.0
}
}
]
},
{
"Items":[
{
"Id":"5b44f410-7034-4972-919d-acac00ead7e9",
"OrderId":"e7791603-ca5f-47c4-9b0c-acac00ead753",
"Type":"ServiceRevenue",
"Amount":{
"Value":25.0,
"Net":25.0,
"Tax":0.0
}
}
]
}
]
I only want to calculate the Amount of the first Item occurrence where the OrderId = 'e7791603-ca5f-47c4-9b0c-acac00ead753'

How can I make a query that returns objects who contain all ids from list

I have two objects : Profile and Tags. Each profile can contain multiple tags. On my search page I can select multiple tags to search on. Now I want a query that get all profiles that have all the selected tags.
So if I use WhereRestrictionOn().IsIn() I get profiles which contains at least 1 of the tags but I need to return profiles which contains all the tags in the list.
I also tried multiple Where conditions for each selected tag but then I get no results at all.
I have no clue how to do this any help is much appreciated!
Structure:
Profile : Id
ProfileTag : ProfileId, TagId
Tag: Id
Mapping Profile
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Agrolink.Application.Models" assembly="Agrolink.Application">
<class name="Agrolink.Application.Models.Profile" lazy="false" table="Profiles" >
<id name="Id" column="Id" >
<generator class="identity" />
</id>
<bag name="Tags" table="ProfileTags" cascade="all-delete-orphan" inverse="true">
<key column="IdProfile" not-null="true"/>
<one-to-many class="Agrolink.Application.Models.ProfileTag" />
</bag>
</class>
</hibernate-mapping>
Mapping ProfileTag
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Agrolink.Application.Models" assembly="Agrolink.Application">
<class name="Agrolink.Application.Models.ProfileTag" lazy="false" table="ProfileTags" >
<id name="Id" column="Id" >
<generator class="identity" />
</id>
<many-to-one name="Profile" class="Agrolink.Application.Models.Profile" column="IdProfile" cascade="save-update" />
<many-to-one name="Tag" class="Agrolink.Application.Models.Tag" column="IdTag" cascade="none" />
</class>
</hibernate-mapping>
Mapping Tag
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Agrolink.Application.Models" assembly="Agrolink.Application">
<class name="Agrolink.Application.Models.Tag" lazy="false" table="Tags" >
<id name="Id" column="Id" >
<generator class="identity" />
</id>
<property name="Name" column="Name" />
<property name="Type" type="Agrolink.Application.Models.TagType, Agrolink.Application" column="IdType" />
<many-to-one name="Parent" class="Agrolink.Application.Models.Tag" column="IdParent" cascade="none" />
<bag name="Children" table="Tags" cascade="all" inverse="true">
<key column="IdParent" not-null="true"/>
<one-to-many class="Agrolink.Application.Models.Tag" />
</bag>
</class>
</hibernate-mapping>
SubQuery to achieve this (Solution):
Profile p = null;
Account a = null;
Institute i = null;
var q = Session.QueryOver(() => p)
.JoinAlias(x => x.Account, () => a)
.JoinAlias(x => x.Institute, () => i)
.Where(x => x.Type == ProfileType.Expert && x.Status == ProfileStatus.Active);
if(_keywordIds.Any())
foreach (var keywordId in _keywordIds)
{
Tag t = null;
var subQ = QueryOver.Of<ProfileTag>()
.JoinAlias(pt => pt.Tag, () => t)
.Where(() => t.Id == keywordId)
.Select(pt => pt.Profile.Id);
q.WithSubquery.WhereProperty(() => p.Id).In(subQ);
}
if (_institute != null) q.Where(() => i.Id == _institute);
if (!string.IsNullOrEmpty(_name)) q.Where(Restrictions.Disjunction()
.Add(Restrictions.Like("a.FirstName", _name + "%"))
.Add(Restrictions.Like("a.LastName", _name + "%"))
);
return (PagedList<Profile>) q.List<Profile>().ToPagedList(_page, _itemsPerPage);
It is almost it, but we need so called Detached QueryOver, which we will get with construction QueryOver.Of
foreach (var keywordId in _keywordIds)
{
//Tag t = null;
var subQ = QueryOver.Of<ProfileTag>()
//.JoinAlias(pt => pt.Tag, () => t)
//.Where(() => t.Id == keywordId)
.Where(x => x.Tag.Id == keywordId)
//.Select(pt => t.Id);
.Select(pt => pt.Profile.Id);
q.WithSubquery.WhereProperty(() => p.Id).In(subQ);
}

How to log WS Security username and SOAP method on Mule

I have an application that will validate username and password to give access to a soap webservice and im trying to log the username and method used, so how to log that info into a database (get user and method)?
this is the code i have so far:
<mule-ss:security-manager
xmlns:mule-ss="http://www.mulesoft.org/schema/mule/spring-security">
<mule-ss:delegate-security-provider
name="jdbc-provider" delegate-ref="authenticationManager" />
</mule-ss:security-manager>
<spring:beans>
<spring:bean id="loggingInInterceptor"
class="org.apache.cxf.interceptor.LoggingInInterceptor" />
<spring:bean id="loggingOutInterceptor"
class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
<spring:bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<spring:property name="driverClassName" value="org.postgresql.Driver" />
<spring:property name="url" value="jdbc:postgresql://127.0.0.1/anydb" />
<spring:property name="username" value="anyuser" />
<spring:property name="password" value="0123456" />
</spring:bean>
<ss:http xmlns:ss="http://www.springframework.org/schema/security"
auto-config="true" use-expressions="true" request-matcher="regex">
<ss:intercept-url pattern="^/services/any/anyservice"
access="hasRole('ROLE_ANY')" />
</ss:http>
<ss:authentication-manager
xmlns:ss="http://www.springframework.org/schema/security" alias="authenticationManager">
<ss:authentication-provider>
<ss:jdbc-user-service data-source-ref="dataSource"
users-by-username-query="
select username, password, enabled
from users where username=?"
authorities-by-username-query="
select u.username, ur.authority from users u, authorities ur
where u.id = ur.user_id and u.username =? " />
</ss:authentication-provider>
</ss:authentication-manager>
</spring:beans>
<jdbc:postgresql-data-source name="postgreName"
user="anyuser" password="0123456" url="jdbc:postgresql://127.0.0.1/anyservice"
transactionIsolation="UNSPECIFIED" doc:name="PostgreSQL Data Source">
</jdbc:postgresql-data-source>
<jdbc:connector name="jdbcConnector" dataSource-ref="postgreName"
validateConnections="false" queryTimeout="10" pollingFrequency="10000"
doc:name="Database">
<reconnect frequency="3000" blocking="false" />
<jdbc:query key="anydb" value="insert into inbound_msgs (ip_from, request_size, modified_request_size, timestamp, url)
values (
#[groovy: return message.getInboundProperty('MULE_REMOTE_CLIENT_ADDRESS').toString()],
#[groovy: return message.getInboundProperty('http.request.old').toString().length()],
#[groovy: return message.getInboundProperty('http.request').toString().length()],
now(),
#[groovy: return message.getInboundProperty('http.context.uri').toString()]);">
</jdbc:query>
</jdbc:connector>
<scripting:transformer name="noopLoggingTransformer"
doc:name="Script">
<scripting:script engine="groovy">
def props = [:]
//props['User-Agent'] = message.getProperty('User-Agent', org.mule.api.transport.PropertyScope.INBOUND)
props['MULE_REMOTE_CLIENT_ADDRESS'] =
message.getProperty('MULE_REMOTE_CLIENT_ADDRESS',
org.mule.api.transport.PropertyScope.INBOUND)
props['http.request'] = message.getProperty('http.request',
org.mule.api.transport.PropertyScope.INBOUND)
props['http.context.uri'] = message.getProperty('http.context.uri',
org.mule.api.transport.PropertyScope.INBOUND)
props['http.request.old'] = message.getProperty('http.request',
org.mule.api.transport.PropertyScope.INBOUND)
muleContext.client.dispatch('vm://log-request.in', payload, props)
message
</scripting:script>
</scripting:transformer>
<flow name="log-request" doc:name="log-request">
<vm:inbound-endpoint path="log-request.in"
doc:name="VM" />
<jdbc:outbound-endpoint exchange-pattern="one-way"
queryKey="anydb" responseTimeout="10000" queryTimeout="10"
connector-ref="jdbcConnector" doc:name="Persist raw message">
</jdbc:outbound-endpoint>
</flow>
<pattern:web-service-proxy name="logBypass" doc:name="logBypass">
<inbound-endpoint address="http://localhost/services/logBypass" exchange-pattern="request-response" transformer-refs="noopLoggingTransformer">
<mule-ss:http-security-filter realm="mule-realm"></mule-ss:http-security-filter>
</inbound-endpoint>
<outbound-endpoint address="http://targetServer/logBypass" exchange-pattern="request-response"/>
</pattern:web-service-proxy>
Mule version 3.4.0
After a few days i came with a solution to my problem:
with:
<scripting:transformer name="noopLoggingTransformer"
doc:name="Script">
<scripting:script engine="groovy">
import org.apache.commons.codec.binary.Base64
def props = [:]
//props['User-Agent'] = message.getProperty('User-Agent', org.mule.api.transport.PropertyScope.INBOUND)
props['MULE_REMOTE_CLIENT_ADDRESS'] =
message.getProperty('MULE_REMOTE_CLIENT_ADDRESS',
org.mule.api.transport.PropertyScope.INBOUND)
props['http.request'] = message.getProperty('http.request',
org.mule.api.transport.PropertyScope.INBOUND)
props['http.context.uri'] = message.getProperty('http.context.uri',
org.mule.api.transport.PropertyScope.INBOUND)
props['http.request.old'] = message.getProperty('http.request',
org.mule.api.transport.PropertyScope.INBOUND)
def headerData = message.getProperty('http.headers',org.mule.api.transport.PropertyScope.INBOUND)
def userName = ""
if (headerData["Authorization"] != null) {
def security = headerData["Authorization"].split(" ")
def bytes = security[1].bytes
Base64 coder = new Base64()
def decodedData = coder.decode(bytes)
def userNamePwd = new String(decodedData)
def userNameSplit = userNamePwd.split(":")
userName = userNameSplit[0]
}
props['userName'] = userName
def method = ""
if (headerData["SOAPAction"] != null) {
method = headerData["SOAPAction"]
}
props['method'] = method
muleContext.client.dispatch('vm://log-request.in', payload, props)
message
</scripting:script>
</scripting:transformer>
That and the code from the question will work perfect on Mule 3.4.0
Remember to change the database to adapt to your necessity.

Using position() to select a specific node while in a for-each loop in xslt not returning expected results

I realize this code isn't the cleanest, but properly refactoring it unfortunately isn't an option.
The issue is that I would expect position() on the second iteration to return a true value. But when using position() it never returns true, as expected on the second iteration.
But if I hard code the selection values, it returns the expected result. Here is an example:
<root>
<MainProducts>
<MainProduct>
<Published>0</Published>
</MainProduct>
<MainProduct>
<Published>1</Published>
</MainProduct>
</MainProducts>
<SubProducts>
<SubProduct>
<IsDefault>1</IsDefault>
</SubProduct>
<SubProduct>
<IsDefault>0</IsDefault>
</SubProduct>
</SubProducts>
</root>
XML content:
<xsl:for-each select="/root/SubProducts/SubProduct">
<script type="text/javascript">
// Always returns false
console.log("Dynamic position " + <xsl:value-of select="position()" /> + " IsDefault: " + ( <xsl:value-of select="/root/MainProducts/MainProduct[position()]/Published" /> == 1 ? "true" : "false" ));
</script>
</xsl:for-each>
<script type="text/javascript">
// Returns false, but expected to return true on second iteration.
console.log("Hard coded position 1 IsDefault: " + ( <xsl:value-of select="/root/MainProducts/MainProduct[1]/Published" /> == 1 ? "true" : "false" ));
// Returns true
console.log("Hard coded position 2 IsDefault: " + ( <xsl:value-of select="/root/MainProducts/MainProduct[2]/Published" /> == 1 ? "true" : "false" ));
</script>
Here is the exact console output:
Dynamic position 1 IsDefault: false
Dynamic position 2 IsDefault: false
Hard coded position 1 IsDefault: false
Hard coded position 2 IsDefault: true
What am I missing here that position() isn't selecting the node properly?
<script type="text/javascript">
// Always returns false
console.log("Dynamic position " +
<xsl:value-of select="position()" /> +
" IsDefault: " +
( <xsl:value-of select="/root/MainProducts/MainProduct[position()]/Published" />
== 1 ? "true" : "false" ));
</script>
In the above code MainProduct[position()] is equivalent to MainProduct[true()] )don't forget that position() is context-sensitive!
So, you are actually evaluating:
<xsl:value-of select="/root/MainProducts/MainProduct/Published" />
and this outputs always the string value of the first Published element that is selected by the XPath expression -- it happens to be 0.
Correct code:
<xsl:variable name="vPos" select="position()"/>
<script type="text/javascript">
// Always returns false
console.log("Dynamic position " +
<xsl:value-of select="position()" /> +
" IsDefault: " +
( <xsl:value-of select=
"/root/MainProducts/MainProduct[position()=$vPos]/Published" />
== 1 ? "true" : "false" ));
</script>
Here is a complete transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:for-each select="/*/SubProducts/SubProduct">
<xsl:variable name="vPos" select="position()"/>
<script type="text/javascript">
console.log("Dynamic position " +
<xsl:value-of select="position()" /> +
" IsDefault: " +
( <xsl:value-of select=
"/*/MainProducts/MainProduct
[position()=$vPos]/Published" />
== 1 ? "true" : "false" ));
</script>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<root>
<MainProducts>
<MainProduct>
<Published>0</Published>
</MainProduct>
<MainProduct>
<Published>1</Published>
</MainProduct>
</MainProducts>
<SubProducts>
<SubProduct>
<IsDefault>1</IsDefault>
</SubProduct>
<SubProduct>
<IsDefault>0</IsDefault>
</SubProduct>
</SubProducts>
</root>
the wanted, correct result is produced:
<script type="text/javascript">
console.log("Dynamic position " +
1 +
" IsDefault: " +
( 0
== 1 ? "true" : "false" ));
</script>
<script type="text/javascript">
console.log("Dynamic position " +
2 +
" IsDefault: " +
( 1
== 1 ? "true" : "false" ));
</script>