Extract node value by calculating absolute position - xslt

My source XML looks:
<test>
<text1>Test</text1>
<text2>Test</text2>
<text2>Test</text2>
<section>
<text1>Test<bold>content</bold></text1>
<text1>Test</text1>
<text2>Test</text2>
<text2>Test</text2>
</section>
</test>
Want to extract the value of 6th node, based on the absolute number of the element (overall count). The absolute number of the element has been identified using <xsl:number level="any" from="/" count="*"/>.

The XPath expression /descendant::*[6] should give you the element you need.
<xsl:template match="/">
<xsl:copy-of select="/descendant::*[6]" />
</xsl:template>
outputs
<text1>Test<bold>content</bold></text1>
Note that this is an example of the difference between descendant:: and // - //*[6] would give you all elements that are the sixth child element of their respective parent, rather than simply the sixth element in the document in depth-first order.

This xslt
<?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:variable name="allElements" select="//element()" />
<xsl:template match="/">
<output>
<xsl:value-of select="$allElements[6]" />
</output>
</xsl:template>
</xsl:stylesheet>
will result in
<?xml version="1.0" encoding="UTF-8"?>
<output>Testcontent</output>

Related

How to use count specific element and get count value on target xml from source xml using xslt?

I wanna read the element count and apply the target xml element from a specific source element.
this is source xml to be read and counting POSEX field
<?xml version="1.0" encoding="UTF-8"?>
<INVOIC01>
<IDOC>
<POSEX>000010</POSEX>
<MENGE>1.000</MENGE>
<MENEE>EA</MENEE>
<GEWEI>KGM</GEWEI>
<BRGEW>13.000</BRGEW>
<PSTYV>TAN</PSTYV>
<WERKS>3000</WERKS>
</IDOC>
<IDOC>
<POSEX>000010</POSEX>
<MENGE>1.000</MENGE>
<MENEE>EA</MENEE>
<GEWEI>KGM</GEWEI>
<BRGEW>13.000</BRGEW>
<PSTYV>TAN</PSTYV>
<WERKS>3000</WERKS>
</IDOC>
</INVOIC01>
my xslt code
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="*"/>
</xsl:template>
<!-- ============================================================================================= -->
<!-- Template: Enter the ordinal number in POSEX-->
<!-- ============================================================================================= -->
<xsl:template match="POSEX">
<D_6066>
<xsl:value-of select="count(preceding::POSEX)+1"/>
</D_6066>
</xsl:template>
</xsl:stylesheet>
outcome xml after run xslt code
<?xml version="1.0" encoding="UTF-8"?>
<D_6066>1</D_6066>
1.000
EA
KGM
13.000
TAN
3000
<D_6066>2</D_6066>
1.000
EA
KGM
13.000
TAN
3000
I want to expect target xml as below after run xslt.
<D_6066>2</D_6066>
If I understand correctly, you want your output document to consist of a single D_6066 element containing the count of the number of POSEX elements in the input document.
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<D_6066>
<xsl:value-of select="count(//POSEX)"/>
</D_6066>
</xsl:template>
</xsl:stylesheet>

XSLT - Get String between commas

How can I get the value 'four' in XSLT?
<root>
<entry>(one,two,three,four,five,six)</entry>
</root>
Thanks in advance.
You didn't specify the XSLT version, so I assume version 2.0.
I also assume that word four is only a "marker", stating from which place
take the result string (between the 3rd and 4th comma).
To get the fragment you want, you can:
Use tokenize function to "cut" the whole content of entry
into pieces, using a comma as the cutting pattern.
Take the fourth element of the result array.
This expression can be used e.g. in a template matching entry.
So the example script can look like below:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="entry">
<xsl:copy>
<xsl:value-of select="tokenize(., ',')[4]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy><xsl:apply-templates select="#*|node()"/></xsl:copy>
</xsl:template>
</xsl:transform>
For your input XML it gives:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<entry>four</entry>
</root>

XSLT for-each always takes only one element

I have XML which contains multiple elements:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<element>
<ip>192.168.188.101</ip>
</element>
<element>
<ip>192.168.188.100</ip>
</element>
</data>
I want to make it to this structure:
<SYNCDW>
<CIDWSet>
<CI>
<CINUM>192.168.188.101</CINUM>
</CI>
<CI>
<CINUM>192.168.188.100</CINUM>
</CI>
</CIDWSet>
</SYNCDW>
But always one element is processed, the first one, although I have for-each.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<SyncCIDW xmlns="http://www.ibm.com/maximo">
<xsl:attribute name="xsi:schemaLocation" namespace="http://www.w3.org/2001/XMLSchema-instance">http://www.ibm.com/maximo</xsl:attribute>
<CIDWSet>
<xsl:for-each select="*[local-name()='data' and namespace-uri()='']/*[local-name()='element' and namespace-uri()='']">
<CI>
<CINUM>
<xsl:value-of select="string(*[local-name()='data' and namespace-uri()='']/*[local-name()='element' and namespace-uri()='']/*[local-name()='ip' and namespace-uri()=''])"/>
</CINUM>
</CI>
</xsl:for-each>
</CIDWSet>
</SyncCIDW>
</xsl:template>
</xsl:stylesheet>
Why I am not getting processed all other elements but only the first one?
Thank you in advance for help
A couple of things:
Inside of the xsl:for-each, the context switches to the element that you are iterating over (in this case, /data/element), so to select the ip element your XPath is relative from the /data/element that you are "standing on" and would simply be ip. The way you had it, it would be looking for /data/element/data/element/ip inside of the xsl:for-each and would not produce any values inside of the <CINUM>.
You can simplify your XPath expressions. If the elements you are addressing are not bound to a namespace, rather than a generic match on any element and a predicate matching the local-name() and namespace-uri()='', just use the simplified XPath data/element.
If you are creating a statically known attribute xsi:schemaLocation with a statically known value, just use the literal declaration inside of the SyncCIDW element literal.
If you are using xsl:value-of it will yield the string value of the selected node. There is no need for the string() function.
Changes applied to your stylesheet:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<SyncCIDW xmlns="http://www.ibm.com/maximo"
xsi:schemaLocation="http://www.ibm.com/maximo">
<CIDWSet>
<xsl:for-each select="data/element">
<CI>
<CINUM>
<xsl:value-of select="ip"/>
</CINUM>
</CI>
</xsl:for-each>
</CIDWSet>
</SyncCIDW>
</xsl:template>
</xsl:stylesheet>

XSLT transforming name value pairs to its corresponding XML

I am new to XSLT I am trying to transform a name value pair to its corresponding XML. This feature is primarily used in case of special extensions to a standard.
The file I want to transform is the following. There are no spaces expected in any of the extNames.
<?xml version="1.0" encoding="UTF-8"?>
<extensionItems xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ExtensionItems.xsd">
<extensionsItem>
<extName> callCode</extName>
<extValue>1</extValue>
<extType>integer</extType>
</extensionsItem>
<extensionsItem>
<extName>callbackType</extName>
<extValue>All</extValue>
<extType>string</extType>
</extensionsItem>
<extensionsItem>
<extName>callbackEmail</extName>
<extValue>me#mine.org</extValue>
<extType>string</extType>
</extensionsItem>
</extensionItems>
to the following:
<ODEventNotificationExtraField>
<callCode> 1</callCode>
<callbackType> All </callbackType>
<callbackEmail> me#mine.org </callbackEmail>
</ODEventNotificationExtraField>
The following stylesheet produces the desired result:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="extensionItems">
<ODEventNotificationExtraField>
<xsl:apply-templates/>
</ODEventNotificationExtraField>
</xsl:template>
<xsl:template match="extensionsItem">
<xsl:element name="{extName}">
<xsl:value-of select="extValue"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

XSLT node Traversal

Here is a snip-it of the XML:
<?xml version="1.0" encoding="iso-8859-1" ?>
<NetworkAppliance id="S123456">
<Group id="9">
<Probe id="1">
<Value>74.7</Value>
</Probe>
</NetworkAppliance>
I want to get the single point value of 74.7. There are many groups with unique ID's and many Probes under that group with unique ID's each with values.
I am looking for example XSLT code that can get me this one value. Here is what i have that does not work:
<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" version="3.2" />
<xsl:template match="NetworkAppliance">
<xsl:apply-templates select="Group[#id='9']"/>
</xsl:template>
<xsl:template match="Group">
Temp: <xsl:value-of select="Probe[#id='1']/Value"/>
<br/>
</xsl:template>
</xsl:stylesheet>
Here is what worked for me in the end:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<xsl:for-each select="NetworkAppliance/Group[#id=9]/Probe[#id=1]">
Value: <xsl:value-of select="Value" />
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Don't forget that you can do select several levels at once. Fixing your XML to:
<?xml version="1.0" encoding="iso-8859-1" ?>
<NetworkAppliance id="S123456">
<Group id="9">
<Probe id="1">
<Value>74.7</Value>
</Probe>
</Group>
</NetworkAppliance>
and using this stylesheet:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" version="3.2" />
<xsl:template match="/">
Temp: <xsl:value-of select="//Group[#id='9']/Probe[#id='1']/Value"/>
<br/>
</xsl:template>
</xsl:stylesheet>
we can pick out that one item you're interested in.
Points to note:
The // part of the expression means that the search for Group nodes takes place throughout the whole tree, finding Group nodes at whatever depth they're at.
The [#id='9'] part selects those Group nodes with id of 9
The Probe[#id='1'] part immediately after that selects those children of the Group nodes it found where the id is 1, and so on.
<xsl:value-of select="/NetworkAppliance/Group[#id=9]/Probe[#id=1]/Value"/>
XSLT is just one of the tools in the box, and nothing without XPath.
the xpath for value of a node is /node/text()
So
<xsl:value-of select="Probe[#id='1']/text()"/>