1

Some of the <attribute> elements in <Type><values> have an associated <condition> element in a <comparison><ComparsionList>. I was able to compare the object and title and get the output but couldn't output the desired output when there is a condition that depends on another value.

Here is my xml input:

<Types xmlns:p="foo">
<Type>
    <title> TestingOne</title>
    <values>
        <attribute name="vala">10</attribute>
        <attribute name="valb">20</attribute>
        <attribute name="valc">30</attribute>
        <attribute name="vald">40</attribute>
    </values>
    <title> TestingTwo</title>
    <values>
        <attribute name="vala">10</attribute>
        <attribute name="valb">20</attribute>
        <attribute name="valc">15</attribute>
        <attribute name="vald">45</attribute>
    </values>
    <title> TestingThree</title>
    <values>
        <attribute name="vala">78</attribute>
        <attribute name="valb">20</attribute>
        <attribute name="valc">60</attribute>
        <attribute name="vald">42</attribute>
    </values>
   <title> TestingFour</title>
    <values>
        <attribute name="vala">1</attribute>
        <attribute name="valb">3</attribute>
        <attribute name="valc">5</attribute>
        <attribute name="vald">7</attribute>
    </values>
 <title> TestingFive</title>
    <values>
        <attribute name="vala">2</attribute>
        <attribute name="valb">4</attribute>
        <attribute name="valc">6</attribute>
        <attribute name="vald">8</attribute>
    </values>

 <title> TestingSix</title>
    <values>
        <attribute name="vala">2</attribute>
        <attribute name="valb">4</attribute>
        <attribute name="valc">6</attribute>
        <attribute name="vald">8</attribute>
    </values>
    </Type>
  <comparison>
    <comparisionList>
        <object>TestingOne</object>
        <condition>valc=30</condition>
        <newName>vald</newName>
        <newValue>60</newValue>
    </comparisionList>

    <comparisionList>
        <object>TestingTwo</object>
        <condition>valb=40 or valb=20</condition>
        <newName>vald</newName>
        <newValue>60</newValue>
    </comparisionList>

    <comparisionList>
        <object>TestingThree</object>
        <newName>vale</newName>
        <newValue>100</newValue>
    </comparisionList>
      <comparisionList>
        <object>TestingFour</object>
        <condition>valc!=3</condition>
        <newName>vald</newName>
        <newValue>9</newValue>
    </comparisionList>

   </comparisionList>
      <comparisionList>
        <object>TestingSix</object>
        <condition>vala!=vala</condition>
        <newName>vald</newName>
        <newValue>20</newValue>
    </comparisionList>

        <comparisionList>
        <object>TestingSix</object>
        <condition>!valb</condition>
        <newName>vald</newName>
        <newValue>1000</newValue>
    </comparisionList>
 </comparison>
 </comparison>

 </Types>

Here my xsl:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:p="foo" xmlns:ns1="bar">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/Types">
    <objects>
        <xsl:for-each select="/Type">
                  <xsl:element name="{title}">
                    <xsl:for-each select="values/attribute">
                        <xsl:element name="{@name}">
                            <xsl:value-of select="text()"/>
                        </xsl:element>
                    </xsl:for-each>
                    <xsl:variable name="attributes" select="values/*"/>
                    <xsl:variable name="newPath" select="/Types/Type/[object=$attributes]"/>
                    <template>
                        <xsl:value-of select="$newPath/newName"/>
                        <xsl:value-of select="$newPath/newValue"/>
                    </template>
                </xsl:element>
             </xsl:for-each>
    </objects>
 </xsl:template>
 </xsl:stylesheet>

Here is the expected output:

<?xml version="1.0" encoding="UTF-8"?>
<template>
<testingone>
<vala>10</vala>
<valb>20</valb>
<valc>30</valc>
<vald>60</vald>
</testingone>

<testingTwo>
<vala>10</vala>
<valb>20</valb>
<valc>15</valc>
<vald>60</vald>
</testingTwo>

<testingThree>
<vala>78</vala>
<valb>20</valb>
<valc>60</valc>
<vald>100</vald>
</testingThree>
</template>
Parker
  • 7,244
  • 12
  • 70
  • 92
  • The input data and xsl are not valid xml. Your selector p:objectSet/p:objects/p:object does not exist in your input document. – terrywb Sep 23 '14 at 18:33
  • Are you actually asking how to evaluate strings such as `valb=40 or valb=20`, as shown in your `condition` elements? – Tim C Sep 23 '14 at 19:21
  • That's correct TIM and compare them with in – user4071541 Sep 23 '14 at 19:39
  • 1
    New user, old question: http://stackoverflow.com/questions/25921099/xsl-tokenize-the-codition-attribute-with-xml-input-file#comment40578096_25921099 – michael.hor257k Sep 23 '14 at 19:53

1 Answers1

1

Just to give a possible solution to get the desired output - I won't provide a full solution, but part of it. In your comparison list are 2 different approaches (having a condition that should be evaluated or just replacing or adding without a condition, as for the 3d group), your expected ouput doesn't match what I would expect for the 3rd group:

<comparisionList>
    <object>TestingThree</object>
    <newName>vale</newName>
    <newValue>100</newValue>
</comparisionList>

So either you would like to append <vale>100</vale> to the TestingThree-group or it's a typo as you mention you would expect to have <vald>100</vald>.
For both options I would like to let it up to you how to adjust the following in case it'd work for you as almost expected, and it should be possible to add this easily.
And though I know it's not the best solution it at least offers a possible approach and already has the requested output for testingOne and TestingTwo.

Following XSLT

<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="/*">
  <xsl:apply-templates select="Type"/>
</xsl:template>

<xsl:template match="Type">
 <OutPut>
   <xsl:apply-templates select="values"/>
 </OutPut>
</xsl:template>

<xsl:template match="values">
 <xsl:variable name="testName"  
      select="normalize-space(./preceding-sibling::title[1])"/>
 <xsl:element name="{$testName}">
  <xsl:variable name="checkIfCondition">
    <xsl:apply-templates  select="./attribute" mode="attributeCheck">
      <xsl:with-param name="groupName" select="$testName"/>
      <xsl:with-param name="toBeChecked" select="'shouldReplace'"/>
    </xsl:apply-templates>
 </xsl:variable>

 <xsl:variable name="checkConditionName">
   <xsl:apply-templates  select="./attribute" mode="attributeCheck">
    <xsl:with-param name="groupName" select="$testName"/>
    <xsl:with-param name="toBeChecked" select="'shouldReplaceName'"/>
   </xsl:apply-templates>
 </xsl:variable>

 <xsl:variable name="checkConditionValue">
   <xsl:apply-templates  select="./attribute" mode="attributeCheck">
    <xsl:with-param name="groupName" select="$testName"/>
    <xsl:with-param name="toBeChecked" select="'shouldReplaceValue'"/>
   </xsl:apply-templates>
 </xsl:variable>

 <xsl:choose>
   <xsl:when test="$checkIfCondition ='true'">
      <xsl:apply-templates  select="./attribute" mode="attributeChange">
         <xsl:with-param name="groupName" select="$testName"/>
         <xsl:with-param name="changeName" select="$checkConditionName"/>
         <xsl:with-param name="changeValue" select="$checkConditionValue"/>
      </xsl:apply-templates>
   </xsl:when>
   <xsl:otherwise>
      <xsl:apply-templates  select="./attribute" mode="attributes"/>
   </xsl:otherwise>
  </xsl:choose>
 </xsl:element>
</xsl:template>

<xsl:template match="attribute" mode="attributeCheck">
<xsl:param name="groupName"/>
<xsl:param name="toBeChecked" select="'default'"/>
<xsl:variable name="testGroupName" select="$groupName"/>
<xsl:variable name="attributeName" select="."/>
<xsl:variable name="testCondition" 
  select="normalize-space(//comparisionList/object[normalize-space(.)
   =$testGroupName]/parent::*/condition)"/>
<xsl:variable name="conditionNewName" 
   select="normalize-space(//comparisionList/object[normalize-space(.)
  =$testGroupName]/parent::*/newName)"/>
<xsl:variable name="conditionNewValue" 
  select="normalize-space(//comparisionList/object[normalize-space(.)
 =$testGroupName]/parent::*/newValue)"/>
<xsl:variable name="conditionRules" select="tokenize($testCondition,'or')"/>
<xsl:for-each select="tokenize($testCondition,'or')">
  <xsl:variable name="conditionParams" 
       select="tokenize(normalize-space(.),'=')"/>
  <xsl:variable name="conditionName" select="$conditionParams[1]"/>
  <xsl:variable name="conditionValue" select="$conditionParams[2]"/>
  <xsl:choose>
    <xsl:when test="$attributeName/@name = $conditionName 
              and $attributeName = $conditionValue">
      <xsl:choose>
         <xsl:when test="$toBeChecked='shouldReplace' ">
           <xsl:text>true</xsl:text>
         </xsl:when>
         <xsl:when test="$toBeChecked='shouldReplaceName'">
           <xsl:value-of select="$conditionNewName"/>
         </xsl:when>
         <xsl:when test="$toBeChecked='shouldReplaceValue'">
           <xsl:value-of select="$conditionNewValue"/>
         </xsl:when>
         <xsl:otherwise></xsl:otherwise>
  </xsl:choose>
 </xsl:when>
 <xsl:otherwise></xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>

<xsl:template match="attribute" mode="attributes">
<xsl:param name="groupName"/>
<xsl:variable name="testGroupName" select="$groupName"/>
<xsl:value-of select="$testGroupName"/>
<xsl:element name="{./@name}">
  <xsl:value-of select="."/>
</xsl:element>
</xsl:template>

<xsl:template match="attribute" mode="attributeChange">
<xsl:param name="groupName"/>
<xsl:param name="changeName"/>
<xsl:param name="changeValue"/>
<xsl:choose>
  <xsl:when test="$changeName = ./@name">
    <xsl:element name="{./@name}">
      <xsl:value-of select="$changeValue"/>
    </xsl:element>
  </xsl:when>
  <xsl:otherwise>
   <xsl:element name="{./@name}">
    <xsl:value-of select="."/>
   </xsl:element>
  </xsl:otherwise>
 </xsl:choose>
</xsl:template>
</xsl:stylesheet>

Output:

<?xml version="1.0" encoding="UTF-8"?>
<OutPut>
 <TestingOne>
  <vala>10</vala>
  <valb>20</valb>
  <valc>30</valc>
  <vald>60</vald>
 </TestingOne>
 <TestingTwo>
  <vala>10</vala>
  <valb>20</valb>
  <valc>15</valc>
  <vald>60</vald>
 </TestingTwo>
 <TestingThree>
  <vala>78</vala>
  <valb>20</valb>
  <valc>60</valc>
  <vald>42</vald>
 </TestingThree>
</OutPut>

Though it's possibly obvious how this approach works, just a short explanation: At first check if there is a condition given in the comparison list to replace a value in the testgroup. If not, just create the elements from the group without any changes. If a condition is given, apply a template in a different mode on all attributes and set as parameters the name of the element that should be changed and the new value for this element.

matthias_h
  • 11,356
  • 9
  • 22
  • 40
  • Thanks for the update but I get the following error trying to run it 11:40:06,709 ERROR [main] JAXPSAXProcessorInvoker - Error checking type of the expression 'funcall(tokenize, [variable-ref(testCondition/string), literal-expr(or)])'. javax.xml.transform.TransformerConfigurationException: Error checking type of the expression 'funcall(tokenize, [variable-ref(testCondition/string), literal-expr(or)])'. – user4071541 Sep 24 '14 at 15:42