Remove internal node In XSLT [closed] - xslt

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I want to to remove internal node using xslt.
Input :
<row>
<entry align="left" namest="3" valign="middle">
<p type="Table Head">
<c type="_Table Green grid ALL">Medium–low</c>
</p>
</entry>
</row>
Output should be:
<row>
<entry align="left" namest="3" valign="middle">
<p type="Table Head">
Medium–low
</p>
</entry>
</row>
I used <xsl:copy-of> to perform this. But it copies with <c>.
The thing I want to do is remove <c> node. I am using XSLT 2.0

Try It
<?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" indent="yes" encoding="UTF-8"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="c">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>

Related

XSLT: How to peek nested element

That's my xml I need to apply an xslt:
<document>
<component>
<structuredBody>
<component>
<section>
<identifier code="S001"/>
<...>
</section>
</component>
</structuredBody>
</component>
</document>
As you can see, here there's a lot of nested structure I don't need.
What I'm only need is to peek section element where section>identifier.code = "S001".
I'd like to peek my desired element without taking care of upper structure.
I'm using this xslt but it's not peeking my desired section element:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:value-of select="//section[identifier/#code = 'S001']"/>
</xsl:template>
</xsl:stylesheet>
But I'm getting:
<?xml version="1.0" encoding="UTF-8"?>
Above example was a reduced effort to simplify my problem:
<document>
<component>
<structuredBody>
<component>
<section>
<identifier code="S001"/>
<table>
<tbody>
<tr>
<td>attribute1</td>
<td>value1</td>
</tr>
<tr>
<td>attribute2</td>
<td>value2</td>
</tr>
<tr>
<td>attribute3</td>
<td>value3</td>
</tr>
</tbody>
</table>
</section>
<section>
<identifier code="S002"/>
<table>
...
</table>
</section>
</component>
</structuredBody>
</component>
</document>
What I really need is to get something like:
<person> <!-- -> section-->
<attribute key="attribute1">value1</attribute>
<attribute key="attribute2">value2</attribute>
<attribute key="attribute3">value3</attribute>
</person>
Any ideas?
Try:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="/">
<xsl:for-each select="//section[identifier/#code='S001']">
<person>
<xsl:for-each select="//td[1]">
<attribute key="{.}"><xsl:value-of select="../td[2]"/></attribute>
</xsl:for-each>
</person>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Remark: this is the solution to the edited post.

Remove nodes without a body in xslt [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I want to find that nodes which have not a body using XSLT.
Input:
<p type="list_number_unn"/>
<p type="list_number_unn">
<b>Text</b>
</p>
<p type="list_number_unn"/>
<p type="list_number_unn">
<b>Text2</b>
</p>
<p type="list_number_unn">
<b>Text3</b>
</p>
Desired Output :
<p type="list_number_unn">
<b>Text</b>
</p>
<p type="list_number_unn">
<b>Text2</b>
</p>
<p type="list_number_unn">
<b>Text3</b>
</p>
I have no idea how to do this. I am using XSLT 2.0
Try It
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(descendant::text()[normalize-space()])]" />
</xsl:stylesheet>
USE It
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="xml" omit-xml-declaration="no" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(descendant::text())]" />
</xsl:stylesheet>

extract the value of an element node via XPath?

Source-XML:
<data>
<item>
<values>
<element1>
<language>EN</language>
<text>text</text>
</element1>
<element2>
<language>DE</language>
<text>Text</text>
</element2>
</values>
</item>
<item>
<values>
<element5>
<language>EN</language>
<text>description</text>
</element5>
<element6>
<language>DE</language>
<text>Beschreibung</text>
</element6>
</values>
</item> </data>
I want to get all the elements in language 'EN'. First I have a loop, where I saved the elment names in a variable. In the next step I want to get only the elements in language "EN". I need in the result of this step only the element-name and text which have the language 'EN' to build a table.
I tried this:
<xsl:param name="element" select="'element1'"/>
<xsl:template match="/">
<xsl:if test="data/item/values[local-name()=$element]/language[text()='EN']">
</xsl:if>
</xsl:template>
And the output XSLT should be something like:
<table id="123">
<tgroup cols="2">
<colspec colname="c1" colnum="1" colwidth="1.0*"/>
<colspec colname="c2" colnum="2" colwidth="1.0*"/>
<thead>
<row>
<entry>Name</entry>
<entry>Values</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<ph>element1</ph>
</entry>
<entry>text</entry>
</row>
<row>
<entry>
<ph>element5</ph>
</entry>
<entry>description</entry>
</row>
</tbody>
</tgroup>
</table>
I know that there are other ways to solve this problem. But for other steps in the transformation it is important to test every element separately.
Thanks in advance!
<xsl:output method="xml" indent="yes"/>
<xsl:template match="data">
<xsl:for-each-group select="item" group-by="values/*[language = 'EN']">
<xsl:for-each select="current-group()">
<xsl:element name="{current-group()/values/*[language = 'EN']/local-name()}">
<language>
<xsl:value-of select="descendant::language[text() = 'EN']"/>
</language>
<txt>
<xsl:value-of select="current-group()/values/*[language = 'EN']/text"/>
</txt>
</xsl:element>
</xsl:for-each>
</xsl:for-each-group>
</xsl:template>
You may do like this
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common" version="1.0">
<xsl:output indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="/">
<xsl:variable name="ENelements">
<xsl:for-each select="/data/item/values/*[language='EN']">
<element name="{local-name()}"><xsl:value-of select="text" /></element>
</xsl:for-each>
</xsl:variable>
<table id="123">
<tgroup cols="2">
<colspec colname="c1" colnum="1" colwidth="1.0*"/>
<colspec colname="c2" colnum="2" colwidth="1.0*"/>
<thead>
<row>
<entry>Name</entry>
<entry>Values</entry>
</row>
</thead>
<tbody>
<xsl:for-each select="exsl:node-set($ENelements)/*">
<row>
<entry>
<ph><xsl:value-of select="#name" /></ph>
</entry>
<entry><xsl:value-of select="." /></entry>
</row>
</xsl:for-each>
</tbody>
</tgroup>
</table>
</xsl:template>
</xsl:stylesheet>
http://xsltfiddle.liberty-development.net/jyRYYig
AFAICT, it could be simply:
XSLT 1.0
<xsl:stylesheet version="1.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="/data">
<table id="123">
<tgroup cols="2">
<colspec colname="c1" colnum="1" colwidth="1.0*"/>
<colspec colname="c2" colnum="2" colwidth="1.0*"/>
<thead>
<row>
<entry>Name</entry>
<entry>Values</entry>
</row>
</thead>
<tbody>
<xsl:for-each select="item">
<xsl:variable name="elem" select="values/*[language='EN']" />
<row>
<entry>
<ph>
<xsl:value-of select="name($elem)"/>
</ph>
</entry>
<entry>
<xsl:value-of select="$elem/text"/>
</entry>
</row>
</xsl:for-each>
</tbody>
</tgroup>
</table>
</xsl:template>
</xsl:stylesheet>

xslt calculating insurance writeoff not working

I am trying to calculate the contractual write off for medical insurance but the calculation doesn't seem to be working. For example, I need to take the value of the charge attribute on the <charge> tag and subtract the value of the amount attribute on the <adjustment> tag but only when the group and code attributes on the <adjustment> tag are: group ='CO' and code = '45' or '385'
I was able to get everything but the calculations working. I've tried looking at several answers on this forum but am obviously missing something. Any help would be appreciated.
Here is my XML (simplified):
<result check_number="05173408" ...>
<claim ... total_charge="720" total_paid="43">
<charge charge="200">
<adjustment amount="125" code="45" group="CO" />
<adjustment amount="35" code="385" group="CO" />
<adjustment amount="20" code="3" group="PR" />
</charge>
<charge charge="70">
<adjustment amount="70" code="204" group="PR" />
</charge>
<charge charge="300">
<adjustment amount="273" code="45" group="CO" />
<adjustment amount="15" code="3" group="PR" />
</charge>
<charge charge="150">
<adjustment amount="139" code="45" group="CO" />
</charge>
</claim>
</result>
Here is my xslt to date:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<!-- maps to the beginning result tag -->
<xsl:for-each select="/result/claim/charge">
<!-- amount allowed by the insurance for line item -->
<COL>
<DATA>
<xsl:apply-templates select="adjustment" mode="calcAdjTotal" >
</xsl:apply-templates>
</DATA>
</COL>
</xsl:for-each>
<!-- Template created to test Parfait's suggestion -->
<xsl:template match="adjustment" mode="calcAdjTotal" >
<xsl:variable name="condition" select="adjustment[#group='CO' and (#code='45' or #code='385')]"></xsl:variable>
<xsl:value-of select="../#charge - sum($condition/#amount)" />
</xsl:if>
</xsl:template>
</xsl:template>
</xsl:stylesheet>
Here is my output: (updated output)
<COL>
</DATA>
</COL>
<COL>
</DATA>
</COL>
<COL>
</DATA>
</COL>
<COL>
</DATA>
</COL>
Here's what I want to get:
<COL>
<DATA>
40
</DATA>
</COL>
<COL>
<DATA>
</DATA>
</COL>
<COL>
<DATA>
27
</DATA>
</COL>
<COL>
<DATA>
11
</DATA>
</COL>
The format will then be used to import data into Filemaker.
Consider wrapping your conditional equation in an <xsl:if>. Additionally, you can do so with a variable storing the conditional value to avoid repetition:
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output version="1.0" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<ROOT>
<xsl:apply-templates select="*"/>
</ROOT>
</xsl:template>
<xsl:template match="charge">
<xsl:variable name="condition" select="adjustment[(#code='45' or #code='385') and #group='CO']"/>
<COL>
<DATA>
<xsl:if test="$condition">
<xsl:value-of select="#charge - sum($condition/#amount)"/>
</xsl:if>
</DATA>
</COL>
</xsl:template>
</xsl:transform>
I am guessing (!) you want something like:
XSLT 1.0
<xsl:stylesheet version="1.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="/result">
<RESULT>
<xsl:for-each select="claim/charge">
<ROW>
<COL>
<DATA>
<xsl:value-of select="#charge - sum(adjustment[#group='CO' and (#code='45' or #code='385')]/#amount)" />
</DATA>
</COL>
</ROW>
</xsl:for-each>
</RESULT>
</xsl:template>
</xsl:stylesheet>
Applied to your input example, the result will be:
<?xml version="1.0" encoding="UTF-8"?>
<RESULT>
<ROW>
<COL>
<DATA>40</DATA>
</COL>
</ROW>
<ROW>
<COL>
<DATA>70</DATA>
</COL>
</ROW>
<ROW>
<COL>
<DATA>27</DATA>
</COL>
</ROW>
<ROW>
<COL>
<DATA>11</DATA>
</COL>
</ROW>
</RESULT>
This assumes you want to create a record (with one field) for each charge.
Note that this is not valid FileMaker XML syntax.
-- edited in response to clarifications in comments: --
XSLT 1.0
<xsl:stylesheet version="1.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="/result">
<RESULT>
<xsl:for-each select="claim/charge[adjustment[not(#group='PR')]]">
<ROW>
<COL>
<DATA>
<xsl:value-of select="#charge - sum(adjustment[not(#group='PR')]/#amount)" />
</DATA>
</COL>
</ROW>
</xsl:for-each>
</RESULT>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<RESULT>
<ROW>
<COL>
<DATA>40</DATA>
</COL>
</ROW>
<ROW>
<COL>
<DATA>27</DATA>
</COL>
</ROW>
<ROW>
<COL>
<DATA>11</DATA>
</COL>
</ROW>
</RESULT>

Combining two nodesets in XSL

I have the following XML:
<root>
<row>
<elem>Timestamp</elem>
<elem>ERB.CHW.BTU_CV</elem>
<elem>ERB.CHW.BTU1_CV</elem>
<elem>ERB.HW.BTU_CV</elem>
<elem>ERB.HW.BTU1_CV</elem>
<elem>ERB.KW.DEMAND_CV</elem>
<elem>ERB.KWH.MT_CV</elem>
<elem></elem>
</row>
<row>
<elem>2011/09/30 11:21:13.9062</elem>
<elem>2.307609E+09</elem>
<elem>1880067</elem>
<elem>1.068635E+08</elem>
<elem>1340.386</elem>
<elem>448.8</elem>
<elem>1427723</elem>
<elem></elem>
</row>
</root>
I want to alter it such that the first <row> defines new elements (via <elem>) and each non-empty <elem> that follows provides values - such as:
<root>
<row>
<Timestamp>2011/09/30 11:21:13.9062</Timestamp>
<ERB.CHW.BTU_CV>2.307609E+09</ERB.CHW.BTU_CV>
<ERB.CHW.BTU1_CV>1880067</ERB.CHW.BTU1_CV>
<ERB.HW.BTU_CV>1.068635E+08</ERB.HW.BTU_CV>
<ERB.HW.BTU1_CV>1340.386</ERB.HW.BTU1_CV>
<ERB.KW.DEMAND_CV>448.8</ERB.KW.DEMAND_CV>
<ERB.KWH.MT_CV>1427723</ERB.KWH.MT_CV>
</row>
</root>
Two things to note:
Notice how blank <elem> elements are removed from the source structure.
This should work for any number of <row> nodesets.
I feel like this should be simple, but I'm struggling to even know where to begin. Help?
EDIT: RE: #2 above, I am not looking to duplicate the initial <row> nodeset (which is used to define the new elements). Rather, the solution should work for any <row> nodeset that contains data points (i.e., if the second <row> nodeset was duplicated 5 times in a row).
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vElems" select=
"/*/row[1]/elem[normalize-space()]"/>
<xsl:template match="/*">
<root>
<xsl:apply-templates select="row[position() >1]"/>
</root>
</xsl:template>
<xsl:template match="row">
<row>
<xsl:apply-templates select="$vElems">
<xsl:with-param name="pValues"
select="elem"/>
</xsl:apply-templates>
</row>
</xsl:template>
<xsl:template match="elem">
<xsl:param name="pValues"/>
<xsl:variable name="vPos" select="position()"/>
<xsl:element name="{.}">
<xsl:value-of select="$pValues[$vPos]"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
when applied on the following XML document (the provided plus one more data row):
<root>
<row>
<elem>Timestamp</elem>
<elem>ERB.CHW.BTU_CV</elem>
<elem>ERB.CHW.BTU1_CV</elem>
<elem>ERB.HW.BTU_CV</elem>
<elem>ERB.HW.BTU1_CV</elem>
<elem>ERB.KW.DEMAND_CV</elem>
<elem>ERB.KWH.MT_CV</elem>
<elem></elem>
</row>
<row>
<elem>2011/09/30 11:21:13.9062</elem>
<elem>2.307609E+09</elem>
<elem>1880067</elem>
<elem>1.068635E+08</elem>
<elem>1340.386</elem>
<elem>448.8</elem>
<elem>1427723</elem>
<elem></elem>
</row>
<row>
<elem>2011/09/31 11:22:33.9063</elem>
<elem>3.418609E+10</elem>
<elem>1991073</elem>
<elem>1.068635E+08</elem>
<elem>1340.386</elem>
<elem>452.5</elem>
<elem>169578</elem>
<elem></elem>
</row>
</root>
produces the wanted, correct result:
<root>
<row>
<Timestamp>2011/09/30 11:21:13.9062</Timestamp>
<ERB.CHW.BTU_CV>2.307609E+09</ERB.CHW.BTU_CV>
<ERB.CHW.BTU1_CV>1880067</ERB.CHW.BTU1_CV>
<ERB.HW.BTU_CV>1.068635E+08</ERB.HW.BTU_CV>
<ERB.HW.BTU1_CV>1340.386</ERB.HW.BTU1_CV>
<ERB.KW.DEMAND_CV>448.8</ERB.KW.DEMAND_CV>
<ERB.KWH.MT_CV>1427723</ERB.KWH.MT_CV>
</row>
<row>
<Timestamp>2011/09/31 11:22:33.9063</Timestamp>
<ERB.CHW.BTU_CV>3.418609E+10</ERB.CHW.BTU_CV>
<ERB.CHW.BTU1_CV>1991073</ERB.CHW.BTU1_CV>
<ERB.HW.BTU_CV>1.068635E+08</ERB.HW.BTU_CV>
<ERB.HW.BTU1_CV>1340.386</ERB.HW.BTU1_CV>
<ERB.KW.DEMAND_CV>452.5</ERB.KW.DEMAND_CV>
<ERB.KWH.MT_CV>169578</ERB.KWH.MT_CV>
</row>
</root>
The following stylesheet produces the requested result:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<!-- ignore even-numbered rows -->
<xsl:template match="row[position() mod 2 = 0]"/>
<!-- non-empty elem nodes of odd-numbered rows -->
<xsl:template match="elem[normalize-space()]">
<xsl:variable name="pos" select="position()"/>
<xsl:element name="{text()}">
<xsl:value-of select="../following-sibling::row[1]/elem[$pos]"/>
</xsl:element>
</xsl:template>
<xsl:template match="elem"/>
</xsl:stylesheet>
Explanation:
The Identity Transform is used to copy most nodes through unchanged
All even-numbered rows are initially skipped
When processing the (non-empty) elem elements of each odd-numbered row, we grab the value of the elem at the same position in the row's following sibling