If I have multiple nodes in an xsl document and want to check that they all have a child node that exists, how would you do that with a for-each loop in XSL 2?
<A>
<B>
<C>test</C>
</B>
<B>
<C>test</C>
</B>
</A>
For example in the document above, we want to iterate through all B Nodes in the document and ascertain if C exists with the value 'test' for that B node.
"we want to iterate through all B Nodes in the document and ascertain if C exists with the value 'test' for that B node"
<?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:for-each select="A/B[C='test']">
<!-- Rest of XSLT -->
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
You can add 'tests'/predicates using [].
Related
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>
I am trying to get the output based on two separate nodes in XML using key concept of XSLT
I have below XML
<?xml version="1.0" encoding="UTF-8"?>
<mdti:Input xmlns:mdti="urn:com.workday/multiDocumentTransform/Input">
<mdti:Files xmlns:mdti="urn:com.workday/multiDocumentTransform/Input">
<mdti:EventFiles>
<mdti:File mdti:filename="first.xml" mdti:contentType="text/xml">
<wd:Report_Data xmlns:wd="urn:com.workday/bsvc">
<wd:Report_Entry>
<wd:key>1234</wd:key>
<wd:comp>ABC</wd:comp>
<wd:asof>2021-03-24T04:59:32.179-07:00</wd:asof>
<wd:emplid>33333333</wd:emplid>
<wd:worker_type>EMP</wd:worker_type>
<wd:emp_type>Regular</wd:emp_type>
<wd:orig_hire_dt>2021-11-27</wd:orig_hire_dt>
<wd:rehire_dt>2019-04-01</wd:rehire_dt>
<wd:home_host_class>M</wd:home_host_class>
<wd:service_dt>2014-11-27</wd:service_dt>
</wd:Report_Entry>
</wd:Report_Data>
</mdti:File>
<mdti:File mdti:filename="second.xml" mdti:contentType="text/xml">
<wd:Report_Data xmlns:wd="urn:com.workday/bsvc">
<wd:Report_Entry>
<wd:key>1234</wd:key>
<wd:supervisor_lname>xyz</wd:supervisor_lname>
<wd:hr_status>A</wd:hr_status>
<wd:hr_status_descr>Active</wd:hr_status_descr>
<wd:empl_status>A</wd:empl_status>
<wd:empl_status_descr>Active</wd:empl_status_descr>
<wd:ben_status>A</wd:ben_status>
<wd:home_address_change_dt>2019-07-30</wd:home_address_change_dt>
<wd:location>444</wd:location>
<wd:location_descr>Ind</wd:location_descr>
</wd:Report_Entry>
</wd:Report_Data>
</mdti:File>
</mdti:EventFiles>
</mdti:Files>
</mdti:Input>
**I am using below XSLT for my data. Please let me know if I am missing something and way to do it. The only identifier in each node is the mdti:filename **
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:mdti="urn:com.workday/multiDocumentTransform/Input"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:wd="urn:com.workday/bsvc"
exclude-result-prefixes="#all">
<xsl:key name="share" match="mdti:Input/mdti:Files/mdti:EventFiles/mdti:File/wd:Report_Data/wd:Report_Entry" use="mdti:Input/mdti:Files/mdti:EventFiles/mdti:File/wd:Report_Data/wd:Report_Entry/wd:key"/>
<xsl:template match="/">
<data>
<key>1234</key>
<xsl:copy-of select="key('share', wd:key)/wd:hr_status"/>
<emp_type>Regular</emp_type>
<supervisor_lname>xyz</supervisor_lname>
<hr_status>A</hr_status>
<location>444</location>
</data>
</xsl:template>
</xsl:stylesheet>
You have several mistakes.
First, <xsl:template match="/"> puts you in the context of the root node; from this context, the expression wd:key selects nothing - so your instruction <xsl:copy-of select="key('share', wd:key)/wd:hr_status"/> does nothing.
Next, if you want your key to match nodes in the second file, you should restrict it to match only nodes in the second file. Also, the use attribute must be relative to the matched node.
Furthermore, if you want the result to be in no-namespace, you cannot copy nodes from the input - at least not in XSLT 1.0.
There is more, but these are the ones that stand out immediately.
Consider the following example:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:mdti="urn:com.workday/multiDocumentTransform/Input"
xmlns:wd="urn:com.workday/bsvc"
exclude-result-prefixes="mdti wd">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:key name="entry2" match="mdti:File[#mdti:filename='second.xml']/wd:Report_Data/wd:Report_Entry" use="wd:key"/>
<xsl:template match="/mdti:Input">
<root>
<xsl:for-each select="mdti:Files/mdti:EventFiles/mdti:File[#mdti:filename='first.xml']/wd:Report_Data/wd:Report_Entry">
<data>
<!-- data from file1 -->
<key>
<xsl:value-of select="wd:key"/>
</key>
<emplid>
<xsl:value-of select="wd:emplid"/>
</emplid>
<!-- data from file2 -->
<xsl:variable name="entry2" select="key('entry2', wd:key)" />
<supervisor_lname>
<xsl:value-of select="$entry2/wd:supervisor_lname"/>
</supervisor_lname>
<hr_status>
<xsl:value-of select="$entry2/wd:hr_status"/>
</hr_status>
</data>
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>
Applied to your input example, this will produce:
Result
<?xml version="1.0" encoding="utf-8"?>
<root>
<data>
<key>1234</key>
<emplid>33333333</emplid>
<supervisor_lname>xyz</supervisor_lname>
<hr_status>A</hr_status>
</data>
</root>
You can add fields from both branches as required.
One of the default templates in xslt is the following:
<xsl:template match="*|/">
<xsl:apply-templates/>
</xsl:template>
Why does the match pattern contains the expression for the root node "/"? Doesn't the asterisk "*" capture already all nodes in the document?
I tried to leave it out and there was no difference. Following xslt
<xsl:stylesheet
version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xhtml" indent="yes"/>
<xsl:template match="*">
<xsl:value-of select="./name()"/>
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
and following xml
<?xml version="1.0" encoding="UTF-8"?>
<a>
<b>
</b>
</a>
produces the output:
<?xml version="1.0" encoding="UTF-8"?>a
b
So the root node a gets captured.
As the default axis for a location path is child, *|/ is just an abbreviation for child::*|/. And child::* does not match the root node of a document, just its children.
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()"/>
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="*"/>