Question on XSLT following-sibling - xslt

My XML structure looks like this
<COMPANY>
<COMPANY-DATA>ABC</COMPANY-DATA>
<ID>10800</ISSUE-ID>
<PROJECT-ID/>
</COMPANY-ISSUE-INFO>
</COMPANY>
"COMPANY Node repeats"
What I want to do is I want to do I want to check for COMPANY-DATA='ABC' and get its ID
I tried using
<xsl:value-of select="//COMPANY-DATA/.='ABC'/following-sibling::ID/."/>
But this doesn't seem to work and throwing error
Expression must evaluate to node-set
//COMPANY-DATA/.= -->'ABC'<--
/following-sibling::ID/.
Thanks,
Karthik
Edit: I found the solution
**<xsl:value-of select="//COMPANY-DATA[.='ABC']/following-sibling::ID/."/>**
Thanks

The first thing i noticed ist, that whe snipped you postet is no valid XML. The Element <ID> is closed by the End-Element </ISSUED_ID> and there is a single closing Element </COMPANY-ISSUE-INFO>
But if i get you right, you want to find the ID of the <COMPANY> Element where the <COMPANY-DATA> is ABC. So your Comment on your question should do this. But you could also use
<xsl:value-of select="//COMPANY[COMPANY-DATA='ABC']/ID"/>
This removes the need of having the Comapny-Data and ID in a specific sequence.

<xsl:value-of select="//COMPANY-DATA[.='ABC']/following-sibling::ID/."/>

Related

XSL-FO | FO: Tags are being removed

I'm currently using XSL for a work project and I'm facing an issue.
I'm trying to read values for a database that look like this:
<fo:block font-weight='bold>hello</fo:block>
and it seems that XSL is stripping the <fo:block> element because it gives me text only ( I only see Hello, not in bold, and it doesn't behave like a block element ). I feel like, somehow, that XSL interprets the value read from the DB as a string, and strip of the <fo> tags, leaving my with text only.
Any idea what could be done in order that my styling get preserved?
( Obviously this example have been simplified, the text to be displayed is longer than that )
EDIT : Self answered for future references
Based on the comments you want to change <xsl:value-of select='/fulfill-list/ticket-list/list-item/eventTicketConte‌​nt/xmlTicketContent/‌​ticketdescription'/> to <xsl:copy-of select='/fulfill-list/ticket-list/list-item/eventTicketConte‌​nt/xmlTicketContent/‌​ticketdescription'/> (or perhaps <xsl:copy-of select='/fulfill-list/ticket-list/list-item/eventTicketConte‌​nt/xmlTicketContent/‌​ticketdescription/node()'/>).
As first i wanted to thanks you all to have taken the time to answer me. I'm very very very glad to see SO community is such strong.
I have solved my problem this way :
<xsl:for-each select="/fulfill-list/ticket-list/list-item/eventTicketContent/xmlTicketContent/ticketdescription/node()">
<xsl:copy-of select="child::node()" />
</xsl:for-each>
I don't really know what happened beneath the hood and why the <fo> tags were removed, but they were. Looping through all of them and using <xsl:copy-of> did the trick.
Once again, a big thanks to y'all !

pre-processing script to switch product codes

I have a snippet of code I've inherited and I'm trying to get it to work on multiples of the match pattern and set a tag from looking up a value from a table using another tag. What happens is that, for every item, the same lookup is performed and not the relative one for the node. I can't work out the syntax to work thru all entries and substitute the correct one. It's got to be simple it's just that I am simpler :)
My source xml contains this (within an outer /oomsdoc document node not shown):
<item>
<lineqty> 1</lineqty>
<linesku>BNLP5008 </linesku>
<linecustprod>xxxxxxxxxxxxxxx</linecustprod>
<linedesc>London Pride (Bot500mlx8) </linedesc>
</item>
<item>
<lineqty> 1</lineqty>
<linesku>BNBL5008 </linesku>
<linecustprod>xxxxxxxxxxxxxxx</linecustprod>
<linedesc>Bengal Lancer (Bot500mlx8) </linedesc>
</item>
I want to substitute the xxxxxxxxxxxxxxx in each linecustprod tag with the material from the lookup table using the value of the linesku tag.
This is my lookup table:
<Materials>
<product sku='BNLP5008 ' material='LONDON PRIDE'/>
<product sku='BNBL5008 ' material='BENGAL LANCER'/>
</Materials>
and this is my xslt code.
<xsl:variable name="SkuList" select="document('d:\test\transforms\catalogue.xml')/Materials"/>
<xsl:template match="/oomsdoc/item/linecustprod">
<xsl:variable name="MySku" select="/oomsdoc/item/linesku"/>
<linecustprod>
<xsl:value-of select="$SkuList/product[#sku=$MySku]/#material"/>
</linecustprod>
</xsl:template>
I'm guessing some kind of xsl foreach would work but just can't find a usable example to crib :)
Your guidance again would be appreciated at this point in my frustration :)
Thanks,
Brian.
Changing the variable definition to
<xsl:variable name="MySku" select="../linesku"/>
should be sufficient, this will pull out the linesku that is a sibling to the linecustprod you're currently looking at. As currently defined the variable will contain a node set of all the linesku elements in the document, so the value-of will give you the first entry from $SkuList that matches any entry in the main input file.
In addition to Ian Roberts' answer, please change
<xsl:variable name="SkuList" select="document('d:\test\transforms\catalogue.xml')/Materials"/>
to
<xsl:variable name="SkuList" select="document('/d:\test\transforms\catalogue.xml')/Materials"/>
for some reason, the first throws an error (malformed URL).

Using same data element name within for-each

More for reference than actual need: what is the XPath syntax to allow me to reference an element in a xsl:for-each block when the same element name is used elsewhere?
Please note, unfortunately this must be a 1.0 solution
For example, I have the following simple XML, and I want to match up the items with the same id value...
<data>
<block1>
<item><id>1</id><text>Hello</text></item>
<item><id>2</id><text>World</text></item>
</block1>
<block2>
<item><id>1</id><text>123</text></item>
<item><id>2</id><text>ABC</text></item>
</block2>
</data>
If I have a for-each on the block1, how can I reference both the id within the block1 and the id within the block2?
This will work, but I think it is messy...
<xsl:for-each select="//block1/item">
<xsl:variable name="id" select="id"/>
<xsl:value-of select="text"/> - <xsl:value-of select="//block2/item[id=$id]/text"/>
</xsl:for-each>
With the result of...
Hello - 123
World - ABC
Is there a simplified way of replacing the $id in select="//block2/item[id=$id]/text" so that it is referring to the id element from the for-each?
Another way to do it which you may find clearer, and will probably be faster, is to use keys:
<xsl:key name="b2" match="block2/item" use="id"/>
then
<xsl:value-of select="key('b2', id)/text"/>
What you have is correct and common as it is. There's no need to simplify it further; it's a standard idiom recognized and used by those working with XSLT.

xsl - select node by child

I have a problem selecting just elements of an xml, which contain a specific child node. Asumme the following part of an xml:
<root>
<Navision.Buchungen>
<Saldo>-110867.7500</Saldo>
<Navision.Kontostruktur>
<Bereich>1</Bereich>
</Navision.Kontostruktur>
</Navision.Buchungen>
<Navision.Buchungen>
<Saldo>-3082585.2100</Saldo>
<Navision.Kontostruktur>
<Bereich>2</Bereich>
</Navision.Kontostruktur>
</Navision.Buchungen>
...
</root>
Now I have an xsl part like this to get the sum of 'Saldo':
<xsl:variable name="FACT0" select="sum(//root/Navision.Buchungen/Saldo)"/>
But how can I select just the Saldo for 'Bereich' 1 for example?
Use this XPath:
//root/Navision.Buchungen[Navision.Kontostruktur/Bereich = 1]/Saldo
//root/Navision.Buchungen[Navision.Kontostruktur/Bereich = 1]/Saldo
Edited:
oh already posted.
For further problems you can use one of the online testbeds like this one. And of course good manuals like those from w3schools, also with testbeds for xsl

Using dynamic xpath in XSLT

I am using a variable say xpathvar in the XSLT whose value will be supplied at the time of call to XSLT. How can i achieve this?
My XSLT file looks like -
<xsl:param name="xpathvar"/>
<xsl:param name="keyxpath"/>
<xsl:template match="/">
<listofResults>
<xsl:for-each select="$xpathvar">
<keyvalues><xsl:value-of select="xalan:evaluate(substring-before($keyxpath,'||'))"/></keyvalues>
<keyvalues><xsl:value-of select="xalan:evaluate(substring-after($keyxpath,'||'))"/></keyvalues>
</xsl:for-each>
</listofResults>
</xsl:template>
</xsl:stylesheet>
If I mention the variable in the for-each, it throws error. Please guide how can I achieve this.
Thanks!
According to Global xsl:param containing xpath expression string it can't be done purely with plain old XSLT, you need to use the evaluate extension see: Xalan evaluate expression
I dont think this can be done like this you must use xpath so example would be
<template match="Node[name=$xpathvar]" />
<xsl:for-each select="*[name()=$xpathvar]">
</xsl:for-each>
I think it does not let you use the variable directly because it is not a nodeset.
If I mention the variable in the
for-each, it throws error
In XSLT 1.0 (it looks you are using Xalan), you can iterate over node sets, only. So $xpathvar should be an instance of node set data type.
In XSLT 2.0 you can iterate over sequence (including scalar values).
Also, if the string containing the "dynamic" XPath expression is simple enough (only QName test step, maybe positional predicates) this could be done (as is already answered in SO) with standar XSLT.