I have to copy all the sets where the mail end with "test.com", if there count is greater than 5. I've tried several things, but nothing seems to work.
How can I do this with xslt 1.0?
<root>
<sets>
<set>
<mail>a#test.com</mail>
<foo/>
</set>
<set>
<mail>a#test.net</mail>
<foo/>
</set>
<set>
<mail>b#test.com</mail>
<foo/>
</set>
</sets>
</root>
For example I tried this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:if test="count(/root/sets/set[mail = '*test.com'])">
<root>
<sets>
<xsl:for-each select="/root/sets/set">
<xsl:if test="contains(./mail, 'test.com')">
<xsl:copy-of select="./*"/>
</xsl:if>
</xsl:for-each>
</sets>
</root>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
I have to copy all the sets where the mail end with "test.com".
How about:
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:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="sets">
<xsl:copy>
<xsl:apply-templates select="set[substring-after(mail, '#')='test.com']"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Related
Here's my input XML:
<?xml version="1.0" encoding="UTF-8"?>
<Sync
xmlns="http://schema.infor.com/InforOAGIS/2" languageCode="en-US" versionID="2.8.0">
<Data>
<ID>0001</ID>
<Text>ABCD</Text>
</Data>
</Sync>
And here's my expected outcome:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:Sync xmlns:ns0="http://schema.infor.com/InforOAGIS/2"
languageCode="en-US"
versionID="2.8.0">
<DataArea xmlns:dns="http://schema.infor.com/InforOAGIS/2" xmlns="">
<ID>0001</ID>
<Text>ABCD</Text>
</DataArea>
</ns0:Sync>
My current XSLT as below (https://xsltfiddle.liberty-development.net/nbiE19N).
There are 2 problems:
I have the extra xmlns="" in DataArea element. I only want to add the dns namespace.
I cannot add the ns0 prefix for my namespace
<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="/*:Sync">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*:Sync/*:Data">
<DataArea>
<xsl:namespace name="dns" select="'http://schema.infor.com/InforOAGIS/2'"/>
<ID>
<xsl:value-of select="/*:Sync/*:Data/*:ID"/>
</ID>
<Text>
<xsl:value-of select="/*:Sync/*:Data/*:Text"/>
</Text>
</DataArea>
</xsl:template>
</xsl:stylesheet>
Any suggestion is appreciated!
Does this return the expected result:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="http://schema.infor.com/InforOAGIS/2">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/Sync">
<ns0:Sync xmlns:ns0="http://schema.infor.com/InforOAGIS/2">
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</ns0:Sync>
</xsl:template>
<xsl:template match="Data">
<DataArea xmlns:dns="http://schema.infor.com/InforOAGIS/2">
<xsl:apply-templates/>
</DataArea>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
P.S. I am not sure why you need the xmlns:dns="http://schema.infor.com/InforOAGIS/2" declaration; it's not being used anywhere.
In my XML I want to copy values into one node from another node if both nodes have matching values in some other nodes.
<XML>
<ORG>
<ITM>
<NUM>1</NUM>
<SEQ>10</SEQ>
<VAL>X</VAL>
</ITM>
<ITM>
<NUM>2</NUM>
<SEQ>20</SEQ>
<VAL>Y</VAL>
</ITM>
</ORG>
<NEW>
<ITM>
<NUM>1</NUM>
<SEQ>10</SEQ>
<VAL>QQQ</VAL>
</ITM>
</NEW>
</XML>
This works, but for large documents it might be slow, is there a better way?
<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="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ORG/ITM/VAL">
<xsl:variable name="NUM" select="../NUM"/>
<xsl:variable name="SEQ" select="../SEQ"/>
<VAL>
<xsl:value-of select="../../../NEW/ITM/VAL[../NUM=$NUM and ../SEQ=$SEQ]"/>
</VAL>
</xsl:template>
</xsl:stylesheet>
The result has the value "QQQ" in the ORG/ITM/VAL node since ORG/ITM/NUM and ORD/ITM/SEQ match with NEW/ITM/NUM and NEW/ITM/SEQ
<?xml version="1.0"?>
<XML>
<ORG>
<ITM>
<NUM>1</NUM>
<SEQ>10</SEQ>
<VAL>QQQ</VAL>
</ITM>
<ITM>
<NUM>2</NUM>
<SEQ>20</SEQ>
<VAL/>
</ITM>
</ORG>
<NEW>
<ITM>
<NUM>1</NUM>
<SEQ>10</SEQ>
<VAL>QQQ</VAL>
</ITM>
</NEW>
</XML>
The preferred method to lookup values is to define a key and use it. In the given example, this could be:
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:key name="new-item" match="NEW/ITM" use="concat(NUM, '|', SEQ)" />
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ORG/ITM/VAL">
<xsl:copy>
<xsl:value-of select="key('new-item', concat(../NUM, '|', ../SEQ))/VAL"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
using 1 variable is more faster.
<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="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ORG/ITM/VAL">
<xsl:variable name="NUMSEQ" select="concat(string(../NUM), string(../SEQ))"/>
<VAL>
<xsl:value-of select="../../../NEW/ITM/VAL[concat(string(../NUM), string(../SEQ))=$NUMSEQ]"/>
</VAL>
</xsl:template>
</xsl:stylesheet>
i am a newbie when it comes to XSLT translations, and have been searching with this question for a while, but did not find any answher to it. I have an XML file looking like this:
<item>
<code>I001</code>
<description>DEF</description>
<properties>
<line1>
<key>key 1</key>
<value>value 1</value>
</line1>
<line2>
<key>key 2</key>
<value>value 2</value>
</line2>
</properties>
</item>
The label-software that i need to process this data with does not cope with this kind of leveled xml, so i have to transform it to something like this
<?xml version="1.0" encoding="utf-8"?>
<item>
<code>I001</code>
<description>DEF</description>
<P1_key>key 1</P1_key>
<P1_value>value 1</P1_value>
<P2_key>key 1</P2_key>
<P2_value>value</P2_value>
</item>
So far i have come up with an xsl-file that looks like this:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
<xsl:output method="xml" indent="yes"/>
<!-- Identity rule -->
<xsl:template match="node() | #*">
<xsl:copy>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<!-- special rules ... -->
<xsl:template match="properties/line1/*">
<xsl:element name="P1_{local-name()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="properties/line2/*">
<xsl:element name="P2_{local-name()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
This does only partly what i need (renaming the elements), wit a result looking like this:
<?xml version="1.0" encoding="utf-8"?>
<item>
<code>I001</code>
<description>DEF</description>
<properties>
<line1>
<P1_key>key 1</P1_key>
<P1_value>value 1</P1_value>
</line1>
<line2>
<P2_key>key 1</P2_key>
<P2_value>value</P2_value>
</line2>
</properties>
</item>
What i now would like to now is how to move the renamed elements (P1_key, P1_value, P2_key, P2_value) to the level.
Any hints would be appreciated.
Thanks
How about:
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="/item">
<xsl:copy>
<xsl:copy-of select="code | description"/>
<xsl:for-each select="properties/*/key">
<xsl:element name="P{position()}_key">
<xsl:value-of select="."/>
</xsl:element>
<xsl:element name="P{position()}_value">
<xsl:value-of select="following-sibling::value[1]"/>
</xsl:element>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Or perhaps:
<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="/item">
<xsl:copy>
<xsl:copy-of select="code | description"/>
<xsl:for-each select="properties/*/key">
<xsl:variable name="line-num" select="substring-after(name(..), 'line')" />
<xsl:element name="P{$line-num}_key">
<xsl:value-of select="."/>
</xsl:element>
<xsl:element name="P{$line-num}_value">
<xsl:value-of select="following-sibling::value[1]"/>
</xsl:element>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Of course, if there always will be exactly two lines, you could just spell it out:
<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="/item">
<xsl:copy>
<xsl:copy-of select="code | description"/>
<P1_key>
<xsl:value-of select="properties/line1/key" />
</P1_key>
<P1_value>
<xsl:value-of select="properties/line1/value" />
</P1_value>
<P2_key>
<xsl:value-of select="properties/line2/key" />
</P2_key>
<P2_value>
<xsl:value-of select="properties/line2/value" />
</P2_value>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
BTW, your method could work too, if you add another template:
<xsl:template match="properties | line1 | line2">
<xsl:apply-templates />
</xsl:template>
I need create a recursive transformation in XSL,
input xml
<root><foo1 /><foo2 /><foo3 /></root>
output
<root>
<foo1>
<foo2>
<foo3>
</foo3>
</foo2>
<foo1>
</root>
Thanks a lot for any help...
Try something like this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml"/>
<xsl:template match="/root">
<xsl:copy>
<xsl:apply-templates select="*[1]" />
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="following-sibling::*[1]" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Which will generate the following output:
<?xml version="1.0"?>
<root>
<foo1>
<foo2>
<foo3/>
</foo2>
</foo1>
</root>
I wanted to extract leaf nodes and have them sorted.
My XSL gives unexpected results. How can I solve this?
Input
<root>
<b>
<b33 zzz="2" fff="3"></b33>
<b11></b11>
<b22></b22>
</b>
<a>
<a27></a27>
<a65 fff="0" eee="2" zzz="10"></a65>
<a11></a11>
</a>
</root>
Xsl
<?xml version="1.0" encoding="utf-8"?>
<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="/">
<root>
<xsl:call-template name="leafnodes"/>
</root>
</xsl:template>
<xsl:template match="*[not(*)]|#*" name="leafnodes">
<xsl:copy>
<xsl:apply-templates select="node()">
<xsl:sort select="name()"/>
</xsl:apply-templates>
<xsl:apply-templates select="#*">
<xsl:sort select="name()"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Output (I would expected it to be sorted, it is not)
<root>
<b33 fff="3" zzz="2" />
<b11 />
<b22 />
<a27 />
<a65 eee="2" fff="0" zzz="10" />
<a11 />
</root>
I would expect the nodes in the order a11, a27, a65, b11, b22, b33.
If I leave out the '[not(*)]', the xsl takes all nodes and sorts them properly.
How can this be solved?
To output all element which have no child sorted by name and the attributes also sorted by name. Try this;
<?xml version="1.0" encoding="utf-8"?>
<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="/">
<root>
<xsl:apply-templates select="//*[not(*)]">
<xsl:sort select="name()"/>
</xsl:apply-templates>
</root>
</xsl:template>
<xsl:template match="*|#*">
<xsl:copy>
<xsl:apply-templates select="#*" >
<xsl:sort select="name()"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Which will generate following output:
<root>
<a11/>
<a27/>
<a65 eee="2" fff="0" zzz="10"/>
<b11/>
<b22/>
<b33 fff="3" zzz="2"/>
</root>