How to do splitbyvalue function using XSLT?
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<ACCOUNT>
<xsl:apply-templates select="//RefCoded/RefCode[. = 'WBS']"/>
</ACCOUNT>
</xsl:template>
<xsl:template match="RefCode">
<item>
<BItemNum>
<xsl:value-of select="../../../../LineItemNum/BLineItemNum"/>
</BItemNum>
</item>
</xsl:template>
</xsl:stylesheet>
Output:
<ACCOUNT>
<item>
<BItemNum>00001</BItemNum>
</item>
<item>
<BItemNum>00001</BItemNum>
</item>
<item>
<BItemNum>00002</BItemNum>
</item>
<item>
<BItemNum>00002</BItemNum>
</item>
</ACCOUNT>
<xsl:template match="/">
<ACCOUNT>
<xsl:for-each select="descendant::RefCode[text() = 'WBS']">
<item>
<BItemNum><xsl:value-of select="ancestor::ItemDetail/descendant::BLineItemNum"/></BItemNum>
</item>
</xsl:for-each>
</ACCOUNT>
</xsl:template>
Related
Please note that source xml fieldscome in sequence means one student's info then another student info.
Can you help on the XSLT to break xml as one group node for each student
My Input is Below
<?xml version="1.0" encoding="UTF-8" ?>
<root>
<item>
<columnName>StudentID</columnName>
<value>2356</value>
</item>
<item>
<columnName>StudentName</columnName>
<value>Java</value>
</item>
<item>
<columnName>City</columnName>
<value>Chicago</value>
</item>
<item>
<columnName>StudentID</columnName>
<value>4578</value>
</item>
<item>
<columnName>StudentName</columnName>
<value>Net</value>
</item>
<item>
<columnName>City</columnName>
<value>NewYork</value>
</item>
<item>
<columnName>StudentID</columnName>
<value>5892</value>
</item>
<item>
<columnName>StudentName</columnName>
<value>Office</value>
</item>
<item>
<columnName>City</columnName>
<value>Dallas</value>
</item>
</root>
I need Output
<?xml version="1.0" encoding="UTF-8" ?>
<root>
<Record>
<item>
<columnName>StudentID</columnName>
<value>2356</value>
</item>
<item>
<columnName>StudentName</columnName>
<value>Java</value>
</item>
<item>
<columnName>City</columnName>
<value>Chicago</value>
</item>
</Record>
<Record>
<item>
<columnName>StudentID</columnName>
<value>4578</value>
</item>
<item>
<columnName>StudentName</columnName>
<value>Net</value>
</item>
<item>
<columnName>City</columnName>
<value>NewYork</value>
</item>
</Record>
<Record>
<item>
<columnName>StudentID</columnName>
<value>5892</value>
</item>
<item>
<columnName>StudentName</columnName>
<value>Office</value>
</item>
<item>
<columnName>City</columnName>
<value>Dallas</value>
</item>
</Record>
</root>
Please note that source xml fileds come in sequence means one student info then another student info.
Can you help on the XSLT to break xml as one group node for each student
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="root">
<root>
<Record>
<xsl:apply-templates select="data"/>
</Record>
<Record/>
</root>
</xsl:template>
<xsl:template match="data">
<data>
<xsl:apply-templates select="columnName"/>
<xsl:apply-templates select="value"/>
</data>
</xsl:template>
<xsl:template match="columnName">
<columnName>
<xsl:value-of select="."/>
</columnName>
</xsl:template>
<xsl:template match="value">
<value>
<xsl:value-of select="."/>
</value>
</xsl:template>
</xsl:stylesheet>
Please note that source xml fileds come in sequence means one student info then another student info.
Can you help on the XSLT to break xml as one group node for each student
Assuming that items always come in groups of three, you could do 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="/root">
<xsl:copy>
<xsl:for-each select="item[position() mod 3 = 1]">
<Record>
<xsl:copy-of select=". | following-sibling::item[position() < 3]"/>
</Record>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I am trying to split the file below to 3 items each and also keep the last section the same. Additionally, I also need to Header block that appears at the beginning with each split (except the last).
Input file
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Root>
<List>
<Header>
<test1>a</test1>
</Header>
<Item>
<ItemNumber>
<Number>1</Number>
</ItemNumber>
</Item>
<Item>
<ItemNumber>
<Number>2</Number>
</ItemNumber>
</Item>
<Item>
<ItemNumber>
<Number>3</Number>
</ItemNumber>
</Item>
<Item>
<ItemNumber>
<Number>4</Number>
</ItemNumber>
</Item>
<Item>
<ItemNumber>
<Number>5</Number>
</ItemNumber>
</Item>
</List>
<List>
<EOF MaxMsgPerFile="3" >
</EOF>
</List>
</Root>
Here is what I have tried
<?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" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:variable name="tag">
<xsl:value-of select="/*/*/EOF/#MaxMsgPerFile"/>
</xsl:variable>
<xsl:template match="/Root">
<xsl:copy>
<xsl:for-each select="List[not (EOF)]/Item[position() mod $tag = 1]">
<List>
<xsl:copy-of select="Header"/>
<xsl:copy-of select=". | following-sibling::Item[position() < $tag]"/>
</List>
</xsl:for-each>
<xsl:copy-of select="List[EOF]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I get everything I wanted but I cant see the Header appearing at each split
Here is what is expected
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<List>
<Header>
<test1>a</test1>
</Header>
<Item>
<ItemNumber>
<Number>1</Number>
</ItemNumber>
</Item>
<Item>
<ItemNumber>
<Number>2</Number>
</ItemNumber>
</Item>
<Item>
<ItemNumber>
<Number>3</Number>
</ItemNumber>
</Item>
</List>
<List>
<Header>
<test1>a</test1>
</Header>
<Item>
<ItemNumber>
<Number>4</Number>
</ItemNumber>
</Item>
<Item>
<ItemNumber>
<Number>5</Number>
</ItemNumber>
</Item>
</List>
<List>
<EOF MaxMsgPerFile="3">
</EOF>
</List>
</Root>
Any help is greatly 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:strip-space elements="*"/>
<xsl:template match="/Root">
<xsl:variable name="groupSize" select="List/EOF/#MaxMsgPerFile" />
<xsl:copy>
<xsl:for-each select="List/Item[position() mod $groupSize = 1]">
<List>
<xsl:copy-of select="../Header | . | following-sibling::Item[position() < $groupSize]"/>
</List>
</xsl:for-each>
<xsl:copy-of select="List[EOF]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Need to write an xslt file. Below is the input file:
<assets>
<item>
<child1>some text</child1>
<child2>some text</child2>
<child3>some text</child3>
<child4>some text</child4>
</item>
<item>
<child1>some text</child1>
<child2>some text</child2>
<childx>some text</childx>
</item>
<item>
<child1>some text</child1>
<childx>some text</childx>
<childy>some text</childy>
<childz>some text</childz>
</item>
</assets>
I need to find out all the unique child names of assets/item. The number of children and child name is dynamic under the element (item)
The Output should be as below:
<item>
<columns>
<columnname>child1</columnname>
<columnname>child2</columnname>
<columnname>child3</columnname>
<columnname>child4</columnname>
<columnname>childx</columnname>
<columnname>childy</columnname>
<columnname>childz</columnname>
</columns>
</item>
You can use Muenchian grouping on the element names - something like this:
<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:key name="elements" match="*" use="local-name()" />
<xsl:template match="/">
<item>
<xsl:apply-templates select="assets/item" />
</item>
</xsl:template>
<xsl:template match="item">
<xsl:for-each select="*[count(.|key('elements', local-name())[1]) = 1]">
<columnname>
<xsl:value-of select="name()"/>
</columnname>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Will get you this:
<item>
<columnname>child1</columnname>
<columnname>child2</columnname>
<columnname>child3</columnname>
<columnname>child4</columnname>
<columnname>childx</columnname>
<columnname>childy</columnname>
<columnname>childz</columnname>
</item>
you can use this
<xsl:key name="child" match="item/*" use="name()"/>
<xsl:template match="/">
<item>
<columns>
<xsl:for-each select="//item/*[count(.|key('child', name())[1]) = 1]">
<columnname><xsl:value-of select="name()"/></columnname>
</xsl:for-each>
</columns>
</item>
</xsl:template>
output
<item>
<columns>
<columnname>child1</columnname>
<columnname>child2</columnname>
<columnname>child3</columnname>
<columnname>child4</columnname>
<columnname>childx</columnname>
<columnname>childy</columnname>
<columnname>childz</columnname>
</columns>
</item>
I'm trying to wrap my head around this and I think the easiest way to explain it is to just show you, below. I've seen this but it doesn't always apply due to the fact I have standalone items also at the end which would match.
The seemingly tricky part is Whatever3 to Whatever6, and then Whatever7 and Whatever8, then finally the new position of Whatever9 - they need to be grouped and the original sequence maintained. (Ignore my naming, there is no way to use xsl:sort)
I've considered xsl:for-each with xsl:if inside, but issue is you can't guarantee how many "groups" vs "non-group" items there are.
Thanks!
XML
<root>
<item>
<position>1</position>
<label>Whatever1</label>
</item>
<item>
<position>2</position>
<label>Whatever2</label>
</item>
<item>
<position>3</position>
<label>Whatever3</label>
<marker id="unique1">start_group</marker>
</item>
<item>
<position>4</position>
<label>Whatever4</label>
</item>
<item>
<position>5</position>
<label>Whatever5</label>
</item>
<item>
<position>6</position>
<label>Whatever6</label>
<marker>last_in_group</marker>
</item>
<item>
<position>7</position>
<label>Whatever7</label>
<marker id="unique2">start_group</marker>
</item>
<item>
<position>8</position>
<label>Whatever8</label>
<marker>last_in_group</marker>
</item>
<item>
<position>9</position>
<label>Whatever9</label>
</item>
</root>
Result
<structure>
<item>
<position>1</position>
<label>Whatever1</label>
</item>
<item>
<position>2</position>
<label>Whatever2</label>
</item>
<group position="3" id="unique1">
<item>
<position>1</position>
<label>Whatever3</label>
</item>
<item>
<position>2</position>
<label>Whatever4</label>
</item>
<item>
<position>3</position>
<label>Whatever5</label>
</item>
<item>
<position>4</position>
<label>Whatever6</label>
</item>
</group>
<group position="4" id="uniqueid2">
<item>
<position>1</position>
<label>Whatever7</label>
</item>
<item>
<position>2</position>
<label>Whatever8</label>
</item>
</group>
<item>
<position>**5**</position>
<label>Whatever9</label>
</item>
</structure>
======================
Here is what I have so far, the only problem I have (besides it being messy) is Whatever4 and Whatever5 are showing up outside the Group.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="root">
<structure>
<xsl:apply-templates select="item[not(marker)] | item[marker='start_group']"/>
</structure>
</xsl:template>
<xsl:template match="item[marker='start_group']">
<group>
<xsl:variable name="currentPosition" select="number(position/text())"/>
<xsl:variable name="lastGroup" select="count(following-sibling::*[local-name() = 'item' and marker='last_in_group'][1]/preceding-sibling::*) + 1"/>
<xsl:attribute name="position">
<xsl:value-of select="$currentPosition"/>
</xsl:attribute>
<xsl:attribute name="id">
<xsl:value-of select="marker/#id"/>
</xsl:attribute>
<item>
<position><xsl:value-of select="number(position/text()) - $currentPosition + 1"/></position>
<label><xsl:value-of select="label/text()"/></label>
</item>
<!-- position() gets reset in for-loop, so need to adjust with outer position -->
<xsl:for-each select="following-sibling::item[(position() + $currentPosition) <= $lastGroup]">
<item>
<position><xsl:value-of select="number(position/text()) - $currentPosition + 1"/></position>
<label><xsl:value-of select="label/text()"/></label>
</item>
</xsl:for-each>
</group>
</xsl:template>
<xsl:template match="item[not(marker)]">
<item>
<position><xsl:value-of select="position/text()"/></position>
<label><xsl:value-of select="label/text()"/></label>
</item>
</xsl:template>
</xsl:stylesheet>
I. XSLT 1.0 Solution:
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:key name="kFollowing"
match="item[not(marker[. = 'start_group'])
and
preceding-sibling::*[marker][1]/marker = 'start_group'
]"
use="generate-id(preceding-sibling::*
[marker[. = 'start_group']]
[1])"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="item[marker[. = 'start_group']]">
<group position="{1 +count(preceding-sibling::*[. = 'start_group'])}"
id="{marker/#id}">
<xsl:copy-of select=".|key('kFollowing', generate-id())"/>
</group>
</xsl:template>
<xsl:template match=
"item[not(marker[. = 'start_group'])
and
preceding-sibling::*[marker][1]/marker = 'start_group'
]"/>
</xsl:stylesheet>
when applied on the provided XML document:
<root>
<item>
<position>1</position>
<label>Whatever1</label>
</item>
<item>
<position>2</position>
<label>Whatever2</label>
</item>
<item>
<position>3</position>
<label>Whatever3</label>
<marker id="unique1">start_group</marker>
</item>
<item>
<position>4</position>
<label>Whatever4</label>
</item>
<item>
<position>5</position>
<label>Whatever5</label>
</item>
<item>
<position>6</position>
<label>Whatever6</label>
<marker>last_in_group</marker>
</item>
<item>
<position>7</position>
<label>Whatever7</label>
<marker id="unique2">start_group</marker>
</item>
<item>
<position>8</position>
<label>Whatever8</label>
<marker>last_in_group</marker>
</item>
<item>
<position>9</position>
<label>Whatever9</label>
</item>
</root>
produces the wanted, correct result:
<root>
<item>
<position>1</position>
<label>Whatever1</label>
</item>
<item>
<position>2</position>
<label>Whatever2</label>
</item>
<group position="1" id="unique1">
<item>
<position>3</position>
<label>Whatever3</label>
<marker id="unique1">start_group</marker>
</item>
<item>
<position>4</position>
<label>Whatever4</label>
</item>
<item>
<position>5</position>
<label>Whatever5</label>
</item>
<item>
<position>6</position>
<label>Whatever6</label>
<marker>last_in_group</marker>
</item>
</group>
<group position="1" id="unique2">
<item>
<position>7</position>
<label>Whatever7</label>
<marker id="unique2">start_group</marker>
</item>
<item>
<position>8</position>
<label>Whatever8</label>
<marker>last_in_group</marker>
</item>
</group>
<item>
<position>9</position>
<label>Whatever9</label>
</item>
</root>
II. XSLT 2.0 solution:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<root>
<xsl:for-each-group select="item" group-starting-with=
"*[marker eq 'start_group'
or
not(marker)
and
preceding-sibling::*[marker][1]/marker eq 'last_in_group'
]
">
<xsl:choose>
<xsl:when test="current-group()[1]/marker">
<group position=
"{1 +count(current-group()[1]
/preceding-sibling::*
[marker = 'start_group'])}"
id="{marker/#id}">
<xsl:apply-templates select="current-group()"/>
</group>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</root>
</xsl:template>
</xsl:stylesheet>
When this XSLT 2.0 transformation is applied on the same XML document (above), the same correct result is produced.
I am trying to write a XSLT which extracts items matches the conditions listed in another file.
INPUT FILE (input.xml)
<ItemList>
<Item>
<Product>ABC</Product>
<Price>10.00</Price>
</Item>
<Item>
<Product>DEF</Product>
<Price>20.00</Price>
</Item>
<Item>
<Product>GHI</Product>
<Price>30.00</Price>
</Item>
<Item>
<Product>JKL</Product>
<Price>40.00</Price>
</Item>
</ItemList>
External List File (Codes.xml)
<ProductCodeList>
<ProductCode>ABC</ProductCode>
<ProductCode>JKL</ProductCode>
</ProductCodeList>
Expected Output (output.xml)
<ItemList>
<Item>
<Product>ABC</Product>
<Price>10.00</Price>
</Item>
<Item>
<Product>JKL</Product>
<Price>40.00</Price>
</Item>
</ItemList>
Could you please show me which one is not working?
<xsl:variable name="productCodeList" select="document('Codes.xml')/ProductCodeList/ProductCode" />`
<xsl:template match="/">
<xsl:apply-templates select="/ItemList/Item[Product=$productCodeList]"/>
</xsl:template>
<xsl:template match="/ItemList/Item">
<xsl:copy-of select="."/>
</xsl:template>
This simple (no conditionals, no current()) 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="vProds" select=
"document('file:///c:/temp/delete/ProductList.xml')"/>
<xsl:template match="/">
<ItemList>
<xsl:copy-of select=
"/*/Item
[Product
=
$vProds/*/ProductCode
]
"/>
</ItemList>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<ItemList>
<Item>
<Product>ABC</Product>
<Price>10.00</Price>
</Item>
<Item>
<Product>DEF</Product>
<Price>20.00</Price>
</Item>
<Item>
<Product>GHI</Product>
<Price>30.00</Price>
</Item>
<Item>
<Product>JKL</Product>
<Price>40.00</Price>
</Item>
</ItemList>
and having the provided Productlist.xml stored at c:\temp\delete:
<ProductCodeList>
<ProductCode>ABC</ProductCode>
<ProductCode>JKL</ProductCode>
</ProductCodeList>
produces the wanted, correct result:
<ItemList>
<Item>
<Product>ABC</Product>
<Price>10.00</Price>
</Item>
<Item>
<Product>JKL</Product>
<Price>40.00</Price>
</Item>
</ItemList>
Does that maybe work better?
<xsl:variable name="productCodeList" select="document('Codes.xml')/ProductCodeList/ProductCode" />
<xsl:template match="/">
<xsl:apply-templates select="/ItemList/Item"/>
</xsl:template>
<xsl:template match="/ItemList/Item">
<xsl:if test="$productCodeList[.=current()/Product]">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:template>