Juli: XSLT 1.0 Abweichung Prüfung

Hallo,

wie kann man zwei Werte prüfen, ob diese abweichend sind? -> Betrifft den Knoten "Item.DeliveryDate" und "Item.OrigDeliveryDate".

Wenn ja, soll ein neuer Knoten "LineChangeDeliveryDate" mit dem Wert "yes" erstellt werden, ansonsten mit dem Wert "no".

XML ist:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<OrderResponse>
  <Interchange>    
    <Interchange_Control_Number>5637248870</Interchange_Control_Number>
  </Interchange>
  <HeaderInformation>
    <ConfirmDocNum>SO0009783-1</ConfirmDocNum>   
    <TransportDetails>
      <DeliveryMode>ROU</DeliveryMode>
    </TransportDetails>   
  </HeaderInformation>
  <LineInformation>
    <Item>      
      <DeliveryDate>2020-01-27</DeliveryDate>
      <OrigDeliveryDate>2019-12-07</OrigDeliveryDate>
    </Item>
  </LineInformation>
</OrderResponse>

XML soll:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<OrderResponse>
  <Interchange>    
    <Interchange_Control_Number>5637248870</Interchange_Control_Number>
  </Interchange>
  <HeaderInformation>
    <ConfirmDocNum>SO0009783-1</ConfirmDocNum>   
    <TransportDetails>
      <DeliveryMode>ROU</DeliveryMode>
    </TransportDetails>   
  </HeaderInformation>
  <LineInformation>
    <Item>      
      <DeliveryDate>2020-01-27</DeliveryDate>
      <OrigDeliveryDate>2019-12-07</OrigDeliveryDate>
	  <LineChangeDeliveryDate>yes</LineChangeDeliveryDate>
    </Item>
  </LineInformation>
</OrderResponse>

Vielen Dank

LG Julian

  1. aktuelles 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" standalone="yes" indent="yes"/>
      <xsl:strip-space elements="*" />
        	
      <xsl:key name="header_text" match="HeaderText" use="Text"/>
      <xsl:key name="line_text" match="LineText" use="concat(../LineNum, '|', Text)"/>
      <xsl:key name="allowance_charge_header" match="AllowanceOrCharge_Header" use="concat(Code, '|', Amount)"/>
      <xsl:key name="allowance_charge_line" match="AllowanceOrCharge_Line" use="concat(../LineNum, '|', Code, '|', Amount)"/>
      <xsl:key use="concat(../LineNum, '|', Text)" match="LineText" name="line_text"/>
    	
      <!-- Identity-Template für die nicht explizit benannten Elemente -->
      <xsl:template match="@* | node()">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
      </xsl:template>
    	
      <xsl:template match="HeaderText[generate-id() != generate-id(key('header_text', Text)[1])]" />
      <xsl:template match="LineText[generate-id() != generate-id(key('line_text', concat(../LineNum, '|', Text))[1])]" />
      <xsl:template match="AllowanceOrCharge_Header[generate-id() != generate-id(key('allowance_charge_header', concat(Code, '|', Amount))[1])]" />
      <xsl:template match="AllowanceOrCharge_Line[generate-id() != generate-id(key('allowance_charge_line', concat(../LineNum, '|', Code, '|', Amount))[1])]" />
      <xsl:template match="LineText[generate-id() != generate-id(key('line_text', concat(../LineNum, '|', Text))[1])]"/>
      
    <xsl:template match="LineInformation">
        <xsl:copy>
        <LineChangeDeliveryDate>
      <xsl:choose>
        <xsl:when test="OrigDeliveryDate = DeliveryDate"/>
           <xsl:value-of select="'yes'"/>
        </xsl:when>
        <xsl:otherwise>
           <xsl:value-of select="'no'"/>
        </xsl:otherwise>
      </xsl:choose>
    </LineChangeDeliveryDate>
        <!--copy all other nodes-->
          <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
      </xsl:template>
    	
    	<!-- delete empty nodes -->
    	<xsl:template match="node()|@*">
    		<xsl:copy>
    			<xsl:apply-templates select="node()|@*"/>
    		</xsl:copy>
    	</xsl:template>
     
     <xsl:template match="*[not(@*|*|comment()|processing-instruction()) and normalize-space()='']"/>
    
    </xsl:stylesheet>
    
  2. wie kann man zwei Werte prüfen, ob diese abweichend sind? -> Betrifft den Knoten "Item.DeliveryDate" und "Item.OrigDeliveryDate".

    Wenn ja, soll ein neuer Knoten "LineChangeDeliveryDate" mit dem Wert "yes" erstellt werden, ansonsten mit dem Wert "no".

    Wie ich die Dinge sehe, präsentierst Du DATEN. Du erzeugst hier innerhalb dieser Daten eine Redundanz. Das kann - vor allem in der Zukunft - zu schwer erkennbaren Problemen führen.

    Ich würde das Auswerfen dieser Information dem auswertendem Programm überlassen.

  3. Hi,

    die Bedingung verwendest Du ja schon im nachgelieferten XSLT. Einfach per = für Gleichheit, != für Ungleichheit.

    Und statt das im LineChangeDeliveryDate zu machen, um zwischen yes und no zu unterscheiden, setzt Du um das LineChangeDeliveryDate ein xsl:if rum mit eben dieser Bedingung. Dann wird das LineChangeDeliveryDate nur erzeugt, wenn die Werte unterschiedlich sind.

    cu,
    Andreas a/k/a MudGuard

  4. Hallo Juli,

    wie kann man zwei Werte prüfen, ob diese abweichend sind? -> Betrifft den Knoten "Item.DeliveryDate" und "Item.OrigDeliveryDate".

    Wenn ja, soll ein neuer Knoten "LineChangeDeliveryDate" mit dem Wert "yes" erstellt werden, ansonsten mit dem Wert "no".

    Das reicht für den relevanten Teil aus:

    <?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" standalone="yes" indent="yes"/>
    
      <xsl:template match="@* | node()">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="Item">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
          <LineChangeDeliveryDate>
            <xsl:choose>
              <xsl:when test="OrigDeliveryDate = DeliveryDate">no</xsl:when>
              <xsl:otherwise>yes</xsl:otherwise>
            </xsl:choose>
          </LineChangeDeliveryDate>
        </xsl:copy>
      </xsl:template>
    
    </xsl:stylesheet>
    

    Grüße,
    Thomas

    1. Guten Morgen und danke schon mal für die Unterstützung bisher.

      Versuche nun im zweiten Schritt zu prüfen, ob eines diese ausgegebenen Felder (LineChangeDeliveryDate, LineChangeQty, LineChangeArticle) mit dem Wert yes befüllt sind, wenn dies der Fall ist soll ein neuer Knoten (LineChange) ebenfalls mit dem Wert yes erstellt werden.

      Der Knoten "LineChange" wird mir zwar erstellt, jedoch funktioniert die Abfrage nicht korrekt.

      Habe als Test die Menge bei QtyOrderd (im XML) angepasst.

      XML:

      <?xml version="1.0" encoding="utf-8" standalone="yes"?>
      <OrderResponse>
        <Interchange>    
        </Interchange>
        <HeaderInformation>    
        </HeaderInformation>
        <LineInformation>
          <Item>     
            <LineNum>1</LineNum>      
            <SupplierArticleNumber>BK07050SC40</SupplierArticleNumber>      
            <Quantity>3.00</Quantity>
            <QtyOrdered>3.00</QtyOrdered>
            <DeliveryDate>2019-12-09</DeliveryDate>
            <OrigDeliveryDate>2019-12-09</OrigDeliveryDate>
            <OrigSupplierArticleNumber>BK07050SC40</OrigSupplierArticleNumber>
          </Item>
          <Item>     
            <LineNum>2</LineNum>      
            <SupplierArticleNumber>BK07050SC40</SupplierArticleNumber>      
            <Quantity>3.00</Quantity>
            <QtyOrdered>5.00</QtyOrdered>
            <DeliveryDate>2019-12-09</DeliveryDate>
            <OrigDeliveryDate>2019-12-09</OrigDeliveryDate>
            <OrigSupplierArticleNumber>BK07050SC40</OrigSupplierArticleNumber>
          </Item>    
        </LineInformation>  
      </OrderResponse>
      

      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" standalone="yes" indent="yes"/>
        <xsl:strip-space elements="*" />
      
      
       <xsl:template match="Item">
          <xsl:copy>
          	<LineChangeDeliveryDate>
      			<xsl:choose>
      				<xsl:when test="OrigDeliveryDate = DeliveryDate">no</xsl:when>
      				<xsl:otherwise>yes</xsl:otherwise>
      			</xsl:choose>
      		</LineChangeDeliveryDate>
      		<LineChangeQty>
      			<xsl:choose>
      				<xsl:when test="QtyOrdered = Quantity">no</xsl:when>
      				<xsl:otherwise>yes</xsl:otherwise>
      			</xsl:choose>
      		</LineChangeQty>
          	<LineChangeArticle>
      			<xsl:choose>
      				<xsl:when test="OrigSupplierArticleNumber = SupplierArticleNumber">no</xsl:when>
      				<xsl:otherwise>yes</xsl:otherwise>
      			</xsl:choose>
      		</LineChangeArticle>
              <LineChange>
              	<xsl:choose>
      				<xsl:when test="concat(LineNum, '|', LineChangeDeliveryDate[yes], '|', LineChangeQty[yes], '|', LineChangeArticle[yes])">yes</xsl:when>
      				<xsl:otherwise>no</xsl:otherwise>
      			</xsl:choose>
      		</LineChange>
      <!--copy all other nodes-->
      <xsl:apply-templates select="@* | node()"/>
      	</xsl:copy>
      </xsl:template>
        
          <!-- Identity-Template für die nicht explizit benannten Elemente -->
        <xsl:template match="@* | node()">
          <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
          </xsl:copy>
        </xsl:template>
      
      
      </xsl:stylesheet>
      
      1. Hallo Julian,

        Guten Morgen und danke schon mal für die Unterstützung bisher.

        Versuche nun im zweiten Schritt zu prüfen, ob eines diese ausgegebenen Felder (LineChangeDeliveryDate, LineChangeQty, LineChangeArticle) mit dem Wert yes befüllt sind, wenn dies der Fall ist soll ein neuer Knoten (LineChange) ebenfalls mit dem Wert yes erstellt werden.

        Der Knoten "LineChange" wird mir zwar erstellt, jedoch funktioniert die Abfrage nicht korrekt.

        
        ><LineChange>
        >  <xsl:choose>
        >    <xsl:when test="concat(LineNum, '|', LineChangeDeliveryDate[yes], '|', LineChangeQty[yes], '|', LineChangeArticle[yes])">yes</xsl:when>
        >    <xsl:otherwise>no</xsl:otherwise>
        >  </xsl:choose>
        ></LineChange>
        
        

        Der Test auf concat() ist wahr, wenn der String exisitert, was allen durch die |-Zeichen gegeben ist. Also erscheint hier yes.

        Ein zweiter Schritt wäre denkbar, wenn man das erste Ergebnis-XML nochmals transformiert. Mit XSLT 2.0 könnte man direkt einen Teilbaum erzeugen und auf diesem weitere Operationen anwenden.

        Grüße,
        Thomas

        1. Ist somit mein Wunsch mit XSLT 1.0 nicht möglich?

          Hätte auch folg. probiert (if), jedoch ohne Erfolg:

           <xsl:template match="Item">
              <xsl:copy>        
                      <xsl:if test="concat(OrigDeliveryDate = DeliveryDate, '|', QtyOrdered = Quantity, '|',  OrigSupplierArticleNumber = SupplierArticleNumber)">
                      <LineChange>no</LineChange>                  
                      </xsl:if>
                      <xsl:if test="concat(OrigDeliveryDate != DeliveryDate, '|', QtyOrdered != Quantity, '|',  OrigSupplierArticleNumber != SupplierArticleNumber)">
                      <LineChange>yes</LineChange>                  
                      </xsl:if> 
              	<LineChangeDeliveryDate>
          			<xsl:choose>
          				<xsl:when test="OrigDeliveryDate = DeliveryDate">no</xsl:when>
          				<xsl:otherwise>yes</xsl:otherwise>
          			</xsl:choose>
          		</LineChangeDeliveryDate>
          		<LineChangeQty>
          			<xsl:choose>
          				<xsl:when test="QtyOrdered = Quantity">no</xsl:when>
          				<xsl:otherwise>yes</xsl:otherwise>
          			</xsl:choose>
          		</LineChangeQty>
              	<LineChangeArticle>
          			<xsl:choose>
          				<xsl:when test="OrigSupplierArticleNumber = SupplierArticleNumber">no</xsl:when>
          				<xsl:otherwise>yes</xsl:otherwise>
          			</xsl:choose>
          		</LineChangeArticle>        
          <!--copy all other nodes-->
          <xsl:apply-templates select="@* | node()"/>
          	</xsl:copy>
          </xsl:template>
          
          1. Hallo Julian,

            Ist somit mein Wunsch mit XSLT 1.0 nicht möglich?

            Hätte auch folg. probiert (if), jedoch ohne Erfolg:

            Ich ahne, dass Du diese '|'-Konstrukte wie ODER auffasst. Dann wäre so etwas möglich (sofern diese Elemente im Ausgangsbaum exisitieren):

            <xsl:if test="OrigDeliveryDate = DeliveryDate or QtyOrdered = Quantity or OrigSupplierArticleNumber = SupplierArticleNumber">
              ...
            </xsl:if>
            

            Analog mit and für UND.

            Grüße,
            Thomas

            1. ja, du hast vollkommen recht. Ich habe das "|" wie ein "OR" gesehen. Danke dafür :)

              Jetzt habe ich noch das Thema, dass das "no" nur dann ausgegeben werden darf, wenn kein "yes" vorhanden ist.

              Gibt es bei dir if-abfrage kein else?

              <xsl:template match="Item">
                  <xsl:copy>        
                         
                          <xsl:if test="OrigDeliveryDate != DeliveryDate or  
                                        QtyOrdered != Quantity or  
                                        OrigSupplierArticleNumber != SupplierArticleNumber">
                              <LineChange>yes</LineChange>                  
                          </xsl:if> 
                           <xsl:if test="OrigDeliveryDate = DeliveryDate or 
                                        QtyOrdered = Quantity or 
                                        OrigSupplierArticleNumber = SupplierArticleNumber">
                              <LineChange>no</LineChange>        
                          </xsl:if>
                      <LineChangeDeliveryDate>
              			<xsl:choose>
              				<xsl:when test="OrigDeliveryDate = DeliveryDate">no</xsl:when>
              				<xsl:otherwise>yes</xsl:otherwise>
              			</xsl:choose>
              		</LineChangeDeliveryDate>
              		<LineChangeQty>
              			<xsl:choose>
              				<xsl:when test="QtyOrdered = Quantity">no</xsl:when>
              				<xsl:otherwise>yes</xsl:otherwise>
              			</xsl:choose>
              		</LineChangeQty>
                  	<LineChangeArticle>
              			<xsl:choose>
              				<xsl:when test="OrigSupplierArticleNumber = SupplierArticleNumber">no</xsl:when>
              				<xsl:otherwise>yes</xsl:otherwise>
              			</xsl:choose>
              		</LineChangeArticle>        
              <!--copy all other nodes-->
              <xsl:apply-templates select="@* | node()"/>
              	</xsl:copy>
              </xsl:template>
              

              benötigst du ein xml-beispiel mit meinen testfällen?

              1. Hallo Julian,

                Jetzt habe ich noch das Thema, dass das "no" nur dann ausgegeben werden darf, wenn kein "yes" vorhanden ist.

                Gibt es bei dir if-abfrage kein else?

                Nein, aber dafür eben xsl:choose mit xsl:when (ggf. mehrfach im Sinne von else if) und xsl:otherwise.

                Grüße,
                Thomas

                1. oooohhh mein Fehler, hatte das mit when schon probiert, aber halt noch mit "|" anstatt "or" und natürlich hat es dann nicht geklappt.

                  Zu guter letzt (vorerst 😛) müsste ich jetzt am kopf unter "HeaderInformation" ausgeben, ob es eine änderung unter "Item" gibt. -> Hier müsste aber eine zusätliche prüfung auf die "LineNum" erfolgen, wie mach ich das? 😅

                  XML:

                  <?xml version="1.0" encoding="utf-8" standalone="yes"?>
                  <OrderResponse>  
                    <HeaderInformation>    
                    <Test>1</Test>      
                    </HeaderInformation>
                    <LineInformation>
                      <Item>
                        <LineNum>1</LineNum>      
                        <SupplierArticleNumber>BK07050S8C40</SupplierArticleNumber>
                        <OrigSupplierArticleNumber>BK07050S8C40</OrigSupplierArticleNumber>     
                        <Quantity>3.00</Quantity>
                        <QtyOrdered>3.00</QtyOrdered>
                        <DeliveryDate>2019-12-06</DeliveryDate>
                        <OrigDeliveryDate>2019-12-06</OrigDeliveryDate>   
                      </Item>  
                      <Item>
                        <LineNum>2</LineNum>      
                        <SupplierArticleNumber>BK07050S8C403</SupplierArticleNumber>
                        <OrigSupplierArticleNumber>BK07050S8C403</OrigSupplierArticleNumber>     
                        <Quantity>3.00</Quantity>
                        <QtyOrdered>3.00</QtyOrdered>
                        <DeliveryDate>2019-12-06</DeliveryDate>
                        <OrigDeliveryDate>2019-12-06</OrigDeliveryDate>   
                      </Item>  
                    </LineInformation>
                    </OrderResponse>
                  

                  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" standalone="yes" indent="yes"/>
                    <xsl:strip-space elements="*" />
                  
                   <xsl:template match="HeaderInformation">
                      <xsl:copy>           
                              <Changes>
                          	    <xsl:choose>
                  			    	<xsl:when test="../LineInformation/Item/OrigDeliveryDate != ../LineInformation/Item/DeliveryDate or  
                                                      ../LineInformation/Item/QtyOrdered != ../LineInformation/Item/Quantity or  
                                                      ../LineInformation/Item/OrigSupplierArticleNumber != ../LineInformation/Item/SupplierArticleNumber">yes</xsl:when>
                  				    <xsl:otherwise>no</xsl:otherwise>
                  			    </xsl:choose>
                  		</Changes>              
                  <!--copy all other nodes-->
                  <xsl:apply-templates select="@* | node()"/>
                  	</xsl:copy>
                  </xsl:template>
                  
                   <xsl:template match="Item">
                      <xsl:copy>
                             <LineChange>
                      		    <xsl:choose>
                  			    	<xsl:when test="OrigDeliveryDate != DeliveryDate or  
                                                      QtyOrdered != Quantity or  
                                                      OrigSupplierArticleNumber != SupplierArticleNumber">6</xsl:when>
                  				    <xsl:otherwise>5</xsl:otherwise>
                  			    </xsl:choose>
                  		</LineChange>
                          <LineChangeDeliveryDate>
                  			<xsl:choose>
                  				<xsl:when test="OrigDeliveryDate = DeliveryDate">no</xsl:when>
                  				<xsl:otherwise>yes</xsl:otherwise>
                  			</xsl:choose>
                  		</LineChangeDeliveryDate>
                  		<LineChangeQty>
                  			<xsl:choose>
                  				<xsl:when test="QtyOrdered = Quantity">no</xsl:when>
                  				<xsl:otherwise>yes</xsl:otherwise>
                  			</xsl:choose>
                  		</LineChangeQty>
                      	<LineChangeArticle>
                  			<xsl:choose>
                  				<xsl:when test="OrigSupplierArticleNumber = SupplierArticleNumber">no</xsl:when>
                  				<xsl:otherwise>yes</xsl:otherwise>
                  			</xsl:choose>
                  		</LineChangeArticle>        
                  <!--copy all other nodes-->
                  <xsl:apply-templates select="@* | node()"/>
                  	</xsl:copy>
                  </xsl:template>
                    
                      <!-- Identity-Template für die nicht explizit benannten Elemente -->
                    <xsl:template match="@* | node()">
                      <xsl:copy>
                        <xsl:apply-templates select="@* | node()"/>
                      </xsl:copy>
                    </xsl:template>
                    
                        <!-- delete empty nodes -->
                  	<xsl:template match="node()|@*">
                  		<xsl:copy>
                  			<xsl:apply-templates select="node()|@*"/>
                  		</xsl:copy>
                  	</xsl:template>
                   
                   <xsl:template match="*[not(@*|*|comment()|processing-instruction()) and normalize-space()='']"/>
                  
                  </xsl:stylesheet>
                  

                  vielen vielen dank

                  1. Hallo Julian,

                    Zu guter letzt (vorerst 😛) müsste ich jetzt am kopf unter "HeaderInformation" ausgeben, ob es eine änderung unter "Item" gibt. -> Hier müsste aber eine zusätliche prüfung auf die "LineNum" erfolgen, wie mach ich das? 😅

                    Naja, an passender Stelle auf Item/LineNum prüfen. Ist jetzt schon etwas viel verlangt, zu verstehen, was Du da genau machst. 😉

                    Grüße,
                    Thomas

                    1. Würde gerne pro Item prüfen ob es eine Änderung gab. Meine Abfrage ist aber Item-Übergreifend.

                      Anhand der LineNum erkennt man, dass es ein weiteres Item ist. -> Die LineNum ist fortlaufend, der Knoten Item heißt immer Item.

                      Hoffe, das hilft? :)

                      LG

                      1. Hallo Julian,

                        Würde gerne pro Item prüfen ob es eine Änderung gab. Meine Abfrage ist aber Item-Übergreifend.

                        Anhand der LineNum erkennt man, dass es ein weiteres Item ist. -> Die LineNum ist fortlaufend, der Knoten Item heißt immer Item.

                        Man müsste ja eh im Template HeaderInformation alle Item-Elemente durchgehen, also etwa xsl:for-each und darin xsl:choose. Bei der Abfrage auf yes/no ließe sich auch auf ItemNum zugreifen.

                        Klinke mich jetzt aus.

                        Grüße,
                        Thomas

                        1. alles klar, danke vielmals für deine hilfe. :)