0

INPUT:

<?xml version="1.0" encoding="UTF-8"?>
<comtec>
<record id="1">
<column name="id_task">44422</column>
<column name="capabilityCode">FR-JUNIOR</column>
<column name="ColMiss">miss</column>
<column name="ColHave"/>
<column name="order_externalId">1867139</column>
</record>
<record id="2">
<column name="id_task">44422</column>
<column name="capabilityCode">FR-XXX</column>
<column name="ColMiss"/>
<column name="ColHave">notmiss</column>
<column name="order_externalId">1867139</column>
</record>
<record id="3">
<column name="id_task">44422</column>
<column name="capabilityCode">AVS</column>
<column name="ColMiss"/>
<column name="ColHave">notmiss</column>
<column name="order_externalId">1867139</column>
</record>
<record id="4">
<column name="id_task">60038</column>
<column name="PropertyDescr">ReqMissing</column>
<column name="capabilityCode">FR-AUTOPLAN</column>
<column name="ResCapString">FR-RDV1, FR-GGE1, FR-PARC2, FR-RDV VIP</column>
<column name="ColMiss">miss</column>
<column name="ColHave"/>
<column name="order_externalId">1867454</column>
</record>
<record id="5">
<column name="id_task">60038</column>
<column name="capabilityCode">FR-XXX</column>
<column name="ColMiss">miss</column>
<column name="ColHave"/>
<column name="order_externalId">1867454</column>
</record>
</comtec>

Desired output:

<comtec>
<task_order>
    <id>1867139</id>
    <capabilities>
        <capability>
            <capability_code>FR-JUNIOR</capability_code>
            <available>true</available>
        </capability>
        <capability>
            <capability_code>FR-XXX</capability_code>
            <required>true</required>
        </capability>
        <capability>
            <capability_code>AVS</capability_code>
            <required>true</required>
        </capability>
    </capabilities>
    <task>
        <id>1867139</id>
        <task_kind_code>drive_through</task_kind_code>
    </task>
</task_order>
<task_order>
    <id>1867454</id>
    <capabilities>
        <capability>
            <capability_code>FR-AUTOPLAN</capability_code>
            <available>true</available>
        </capability>
        <capability>
            <capability_code>FR-XXX</capability_code>
            <available>true</available>
        </capability>
    </capabilities>
    <task>
        <id>1867454</id>
        <task_kind_code>drive_through</task_kind_code>
    </task>
</task_order>
</comtec>

Hello. The desired output is based on the following logic: id_task has multiple records a)if only has values int the 'ColMiss' column then build empty capability tag (second record tag in the output) b)if it has values in both 'ColMiss' column and 'ColHave' then build the capability tag with only the values from the 'CapabilityCode' column in the records that have 'ColHave' not null.

I hope it makes sense, i'm still a novice with the keys/var parts of XSL and im working on some examples to understand.

Thank you

UPDATE:

Current XSL - without keys/variables

   <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:output method="xml"/>
   <xsl:key name="record" match="record" use="record/column[@name='id_task']"/>
   <xsl:template match="comtec">
    <!--grouped by id_task-->
    <xsl:for-each select="record[generate-id(.)=
  generate-id(key('record',
  record/column[@name='id_task'])[1])]">
<task_order>
            <id>
                <xsl:value-of select="column[@name='id_task']"/>
            </id>
            <capabilities>
                <!--the fields in capabilities-->
                <xsl:variable name="values" select="key('record',
                  column[@name='id_task'])/
              column[@name='ColMiss']"/>
                <xsl:choose>
                    <xsl:when test="$values ='miss'">
                        <xsl:for-each select="$values ='miss'">
                            <capability>
                                <capability_code>
                                    <xsl:value-of select="column[name='capabilityCode']"/>
                                </capability_code>
                                <available>true</available>
                            </capability>
                        </xsl:for-each>
                    </xsl:when>
                    <xsl:when test="$values =''">
                        <xsl:for-each select="$values =''">
                            <capability>
                                <capability_code>
                                    <xsl:value-of select="column[name='capabilityCode']"/>
                                </capability_code>
                                <required>true</required>
                            </capability>
                        </xsl:for-each>
                    </xsl:when>
                </xsl:choose>
            </capabilities>
        </task_order>
    </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

As you can see the problem is that it won't group the 'capability' tags under one parent but it creates a per record tag, which is normal because of the logic implemented. But I thought there's some other way besides using a key/variable.

Based on this XSL is there a way to go to the desired output?

Thank you again.

user3529643
  • 105
  • 8
  • There are so many fully answered XSLT grouping questions on StackOverflow, all with working code and most with full explanations. Pick one, read it. If you don't understand, pick another one, read that. Repeat. Come back with XSLT code that at the very least *almost* does what you want. – Tomalak Feb 02 '17 at 17:06
  • Hi. I've updated with the XSL i'm working on without keys. – user3529643 Feb 02 '17 at 18:45
  • Yes.. but as I said: Muenchian grouping and `` have been explained so many, many times on Stack Overflow and elsewhere that it's completely impossible that you haven't found anything on how it works. Your have an ordinary one-level grouping task, any SO answer on this topic will be sufficient to get you started. I've explained how keys work in an older answer to a more complex grouping problem ([here](http://stackoverflow.com/questions/948218/xslt-3-level-grouping-on-attributes), scroll down in the thread). There are many other answers to pick and learn from. – Tomalak Feb 02 '17 at 19:09
  • Updated the XSL:tried with the single level grouping but as I said this was the XSL i was working on which i was stuck on...if you'd be so kind to help out. Thank you! – user3529643 Feb 02 '17 at 20:03
  • I could not understand the logic you describe; please edit your question and make it clearer. – michael.hor257k Feb 02 '17 at 20:17

1 Answers1

0

I couldn't fully work out your logic, but the first problem you have is how you have defined your key

<xsl:key name="record" match="record" use="record/column[@name='id_task']"/>

This will look for record elements, by looking for child record elements of them, which doesn't match what you have in your XML. It should be this...

<xsl:key name="record" match="record" use="column[@name='id_task']"/>

Similarly, for when you use this key in the Muenchian grouping...

<xsl:for-each select="record[generate-id(.)=generate-id(key('record', column[@name='id_task'])[1])]">

There is also a problem with your xsl:for-each...

<xsl:for-each select="$values ='miss'">

This is not valid because the result of $values ='miss' is either "true" or "false", and xsl:for-each requires nodes to be selected, not a Boolean.

Anyway, try this XSLT instead. It doesn't give you the result you need because I could quite work out your exact logic, but it might give you a better starting point...

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="record" match="record" use="column[@name='id_task']"/>

<xsl:template match="comtec">
    <!--grouped by id_task-->
    <xsl:for-each select="record[generate-id(.)=generate-id(key('record', column[@name='id_task'])[1])]">
        <task_order>
            <id>
                <xsl:value-of select="column[@name='id_task']"/>
            </id>
            <capabilities>
                <!--the fields in capabilities-->
                <xsl:variable name="values" select="key('record',column[@name='id_task'])/column[@name='ColMiss']"/>
                <xsl:for-each select="key('record',column[@name='id_task'])">
                    <capability>
                        <capability_code>
                            <xsl:value-of select="column[@name='capabilityCode']"/>
                        </capability_code>
                        <xsl:choose>
                            <xsl:when test="$values[. ='miss']">
                                <required>true</required>
                            </xsl:when>
                            <xsl:otherwise>
                                <available>true</available>
                            </xsl:otherwise>
                        </xsl:choose>
                    </capability>
                </xsl:for-each>
            </capabilities>
        </task_order>
    </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Do note, an expression like $values[. =''] if any of the values are blank, not necessarily all of them. If you wanted to test for all blanks, you would have to do not($values[. != '']) (i.e. there doesn't exist one that isn't blank).

Tim C
  • 70,053
  • 14
  • 74
  • 93