I am unsure how to switch from for-each to loop logic with some count logic
Here is the small sample of the xml. The sequence numbers and discount numbers can range greatly. I have already sorted prior so the xml is in the correct order.
<ns2:_x002F_POSDW_x002F_E1BPLINEITEMDISCOUNT002>
<ns2:RETAILSEQUENCENUMBER>1</ns2:RETAILSEQUENCENUMBER>
<ns2:DISCOUNTSEQUENCENUMBER>1</ns2:DISCOUNTSEQUENCENUMBER>
<ns2:DISCOUNTTYPECODE>ZD01</ns2:DISCOUNTTYPECODE>
</ns2:_x002F_POSDW_x002F_E1BPLINEITEMDISCOUNT002>
<ns2:_x002F_POSDW_x002F_E1BPLINEITEMDISCOUNT002>
<ns2:DATAHEADERCOLUMN_SEGNAM>/POSDW/E1BPLINEITEMDISCOUNT002</ns2:DATAHEADERCOLUMN_SEGNAM>
<ns2:RETAILSEQUENCENUMBER>1</ns2:RETAILSEQUENCENUMBER>
<ns2:DISCOUNTSEQUENCENUMBER>2</ns2:DISCOUNTSEQUENCENUMBER>
<ns2:DISCOUNTTYPECODE>Z407</ns2:DISCOUNTTYPECODE>
</ns2:_x002F_POSDW_x002F_E1BPLINEITEMDISCOUNT002>
<ns2:_x002F_POSDW_x002F_E1BPLINEITEMDISCOUNT002>
<ns2:DATAHEADERCOLUMN_SEGNAM>/POSDW/E1BPLINEITEMDISCOUNT002</ns2:DATAHEADERCOLUMN_SEGNAM>
<ns2:RETAILSEQUENCENUMBER>1</ns2:RETAILSEQUENCENUMBER>
<ns2:DISCOUNTSEQUENCENUMBER>3</ns2:DISCOUNTSEQUENCENUMBER>
<ns2:DISCOUNTTYPECODE>Z407</ns2:DISCOUNTTYPECODE>
</ns2:_x002F_POSDW_x002F_E1BPLINEITEMDISCOUNT002>
<ns2:_x002F_POSDW_x002F_E1BPLINEITEMDISCOUNT002>
<ns2:RETAILSEQUENCENUMBER>2</ns2:RETAILSEQUENCENUMBER>
<ns2:DISCOUNTSEQUENCENUMBER>1</ns2:DISCOUNTSEQUENCENUMBER>
<ns2:DISCOUNTTYPECODE>ZD01</ns2:DISCOUNTTYPECODE>
</ns2:_x002F_POSDW_x002F_E1BPLINEITEMDISCOUNT002>
<ns2:_x002F_POSDW_x002F_E1BPLINEITEMDISCOUNT002>
<ns2:DATAHEADERCOLUMN_SEGNAM>/POSDW/E1BPLINEITEMDISCOUNT002</ns2:DATAHEADERCOLUMN_SEGNAM>
<ns2:RETAILSEQUENCENUMBER>2</ns2:RETAILSEQUENCENUMBER>
<ns2:DISCOUNTSEQUENCENUMBER>2</ns2:DISCOUNTSEQUENCENUMBER>
<ns2:DISCOUNTTYPECODE>Z407</ns2:DISCOUNTTYPECODE>
</ns2:_x002F_POSDW_x002F_E1BPLINEITEMDISCOUNT002>
Here is my XSLT
<xsl:for-each select="ns0:idocData/ns2:_x002F_POSDW_x002F_E1POSTR_CREATEMULTIP001GRP">
<xsl:for-each select="ns2:_x002F_POSDW_x002F_E1BPLINEITEMDISCOUNT002">
<ns2:_x002F_POSDW_x002F_E1BPLINEITEMDISCOUNT002>
<ns2:DATAHEADERCOLUMN_SEGNAM><xsl:value-of select="ns2:DATAHEADERCOLUMN_SEGNAM"/></ns2:DATAHEADERCOLUMN_SEGNAM>
<ns2:RETAILSEQUENCENUMBER><xsl:value-of select="ns2:RETAILSEQUENCENUMBER"/></ns2:RETAILSEQUENCENUMBER>
<ns2:DISCOUNTSEQUENCENUMBER><xsl:value-of select="ns2:DISCOUNTSEQUENCENUMBER"/></ns2:DISCOUNTSEQUENCENUMBER>
<ns2:DISCOUNTTYPECODE><xsl:value-of select="ns2:DISCOUNTTYPECODE"/></ns2:DISCOUNTTYPECODE>
</ns2:_x002F_POSDW_x002F_E1BPLINEITEMDISCOUNT002>
</xsl:for-each>
</xsl:for-each>
My requirement is to loop though the xml and where a ns2:DISCOUNTTYPECODE is found to be ZD01 make that ZD11. If there is another ZD01 found within the same ns2:RETAILSEQUENCENUMBER then make the next DISCOUNTTYPECODE = ZD12 and then ZD13 etc. Only on the ZD01 records.
Once the XML then falls onto the next RETAILSEQUENCENUMBER the logic then needs to start again so that ZD01 becomes ZD11.
I'd recommend writing another transform which would preprocess the data to sort and group it using one of the techniques from the dpawson site mentioned above, this would make determining the discount types a lot easier.
Once the data has been grouped and sorted, this transform would be concerned only with any changes to discount types etc. You could then look at how many previous ZD01 siblings there are and infer the new discount type based on the number of previous siblings
0 previous ZD01 elements = ZD11
1 previous ZD01 element = ZD12
etc.
etc.
The previous siblings could also be used to determine whether renumbering needs to start again based on a different retail number value.
Related
I am a beginner to xslt. I am trying to search a long string for value in my case "EMRUPI", and I need to extract the ID prior and populate another field. I'm using the "substring-before" function
i can not seem to extract the value, it returns NULL
This is the data:
PID|1|12345^^^ABCMRN^MRN^|678988^^^DEFMRN^MRN^~111111^^^GHIMRN^MRN^~7777777^^^EMRUPI^CMRN^||
I basically want to find in the PID3 segment (PID3 is the data after the 3rd pipe "|") the text 'EMRUPI' and grab the id prior to that '7777777'.
I want to save it in a variable eg $EMRUPI and put it into PID4 segment which is what i am trying to do here:
here is the script i wrote:
<PID>
<F3>
<xsl:variable name="EMRUPI" select="substring-before(name(),'EMRUPI')" />
<xsl:value-of select="substring-before(name(),'EMRUPI')" />
<L1.1.1><xsl:value-of select="$EMRUPI"/></L1.1.1>
</F3>
<F4><L1.1.1><xsl:value-of select="$EMRUPI"/></L1.1.1></F4>
</PID>
I am stucked with the Nurserostering example in Optaplanner. I would like to change the input XML to play around (for example increase the number of nurses from 30 to 100), and I find it's very complicated to manually edit it, so I think there must be some kind of 'generator', or maybe I should make my own 'XML generator'.
For example I see every node in the sample has a unique id, so if I want to increase the number of nurses, it's not as simple as copying the last Employee node and pasting it 70 times; I should check every id inside and increase it accordingly.
<Employee id="358">
<id>6</id>
<code>6</code>
<name>6</name>
<contract reference="36"/>
<dayOffRequestMap id="359">
<entry>
<ShiftDate reference="183"/>
<DayOffRequest id="360">
<id>18</id>
<employee reference="358"/>
<shiftDate reference="183"/>
<weight>1</weight>
</DayOffRequest>
...
Therefore, I ask, is there any method to generate this (or other) XML?
The best way I could think of is write a small java application where you could load the original dataset, and then add any number of employees you want (using java code of course). At least this is what I do when I need a bigger dataset or when I toy around the model data (because the dataset need to be updated too).
Oh I almost forgot, sometimes I use xml viewer to help me do some manual copy and paste work (it help me a lot since the row is thousand lines).
You looked at the wrong XML file! Instead of taking e.g. data/nurserostering/unsolved/medium01.xml, take data/nurserostering/import/medium01.xml.
<Employees>
<Employee ID="0">
<ContractID>0</ContractID>
<Name>0</Name>
<Skills>
<Skill>Nurse</Skill>
</Skills><
</Employee>
[...]
<DayOffRequests>
<DayOff weight="1">
<EmployeeID>0</EmployeeID>
<Date>2010-01-21</Date>
</DayOff>
[...]
This file can then easily be edited and imported in OptaPlanner.
StudentID ExamID 09/05/2017 08/05/2017 07/05/2017 06/05/2017 05/05/2017
123 AS12 12
123 AS13 13 23
While convert the above using "FOR XML PATH , Elements" in sql statement. I got the error.
error:Column name '09/05/2017' contains an invalid XML identifier as
required by FOR XML; '2'(0x0032) is the first character at fault.
Is there any way I will get XML in format:
<row>
<StudentID>123</StockID>
<LessonID>AS13</LessonID>
<09/05/2017>13</09/05/2017>
<08/05/2017>23</08/05/2017>
<07/05/2017></07/05/2017>
<06/05/2017></06/05/2017>
<05/05/2017></05/05/2017>
</row>
It is a very bad design, to store your date-based values in columns of the student table. Whenever you have to add a column in order to add more data, the design is bad... This should be stored in a related side table, while a PIVOT query constructs this output format, whenever you need it.
And: Avoid culture specific date formats!!!
How should one know, wheter 06/05/2017 is the 6th of May or the 5th of June? Use ISO8601 like 2017-05-06 (which makes it sure, that you think about the 6th of May)
About your question: No, this is impossible!
XML does not allow an element's name like '05/05/2017'. You must start with a non-numeric character or an underscore and several characters like the / are forbidden...
Try to create your XML similar to
<row>
<StudentID>123</StockID>
<LessonID>AS13</LessonID>
<Marks>
<Mark date="2017-05-09">13<Mark>
<Mark date="2017-05-08">23<Mark>
[... more of them ...]
</Marks>
</row>
This error goes back to how to treat strings in the language you wish to program in. In this case once you are inside the brackets(<>) the slash is (/) is a special character and the first set of algorithms that process this (regex) XML identify the slash as an issue thereby throwing the error.
Additionally you may want to consider how you want to treat your objects in XML. First group is the class, the class has many students, and the students take many lessons, and each lesson has a grade. (or in this case it looks like a lesson has many grades, not shown here)
<CLASS>
<STUDENT>
<StudentID>123</StudentID>
<LESSON>
<LessonID>AS12</LessonID>
<DATE>09/05/2017</DATE>
<GRADE>93.00</GRADE>
</LESSON>
<LESSON>
<LessonID>AS12</LessonID>
<DATE>08/05/2017</DATE>
<GRADE>93.00</GRADE>
</LESSON>
</STUDENT>
<STUDENT>
...
</STUDENT>
</CLASS>
I am trying to generate the following structure in an XSLT template.
<ns:e1>
<child1>some value<child1>
<child2>some value<child2>
<child3>some value<child3>
</ns:e1>
or
<ns:e2>
<child1>some value<child1>
<child2>some value<child2>
<child3>some value<child3>
</ns:e2>
or other elements ns:e3 etc (although finite), based on a template parameter (say type). Typically I could use an xls:choose construct. In such a case, I would be duplicating the child elements (whose values are also template parameters).
Is there a way in XSLT to dynamically assume the element name ns:e1 or ns:e2 so that I can put the child elements once in its parent. I could save maintenance effort later if I have change the child elements or values (change once in one place and avoid bugs due to human errors).
Thanks for your help in advance.
Yes, you may use the xsl:element instruction to do that.
Assuming you always want to have <child1>some value<child1><child2>some value<child2><child3>some value<child3> as children for your parent element, you could rewrite your code like so:
<xsl:variable name="elementName">
<!-- compute the element name here ... -->
</xsl:variable>
<!-- Here we create an element having the name computed in variable elementName -->
<xsl:element name="{$elementName}" namespace="http://www.anamespace.com/and/so/on">
<child1>some value<child1>
<child2>some value<child2>
<child3>some value<child3>
</xsl:element>
Is it possible to move the result generated by the XSLT processor. e.g. in the below case i wanted Benefit type="Main" and its child elements to be displayed before Benefit type="Rider"
Two separate templates are applied for Rider and Main, hence i think xsl:sort cannot be applied, since it sorts within a single collection.
<Policy>
<Benefit type="Rider">
<ProductAbbreviatedName>BBB</ProductAbbreviatedName>
<ProductCode>U30</ProductCode>
<ProductName>BBB</ProductName>
</Benefit>
<Benefit type="Main">
<ProductAbbreviatedName>AAA</ProductAbbreviatedName>
<ProductCode>231Y</ProductCode>
<ProductName>AAAA</ProductName>
</Benefit>
</Policy>
Kindly advice on some ideas to perform the desired output. Many thanks.
Just use in your code:
<xsl:apply-templates select="Benefit[#type='Main']"/>
<xsl:apply-templates select="Benefit[#type='Rider']"/>