Search code examples
xmlxsltgroovysap-cpi

SAP CPI (Groovy): How to filter parent node based on grandchild node


I'm using SAP CPI platform and I want to remove the parent node (payload) based on its grandchild nodes (localeId and translation). The input XML provided is like this:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <payload>
      <title>Doc1</title>
      <localizedTitle>
         <localeID>es</localeID>
         <translation>Type 1</translation>
      </localizedTitle>
      <localizedTitle>
         <localeID>en</localeID>
         <translation>Type 1</translation>
      </localizedTitle>
   </payload>
   <payload>
      <title>Doc3</title>
      <localizedTitle>
         <localeID>es</localeID>
         <translation>Type 3</translation>
      </localizedTitle>
      <localizedTitle>
         <localeID>en</localeID>
         <translation>Type 3</translation>
      </localizedTitle>
   </payload>
   <payload>
      <title>Doc4</title>
      <localizedTitle>
         <localeID>es</localeID>
         <translation>Type 1</translation>
      </localizedTitle>
      <localizedTitle>
         <localeID>en</localeID>
         <translation>Type 1</translation>
      </localizedTitle>
   </payload>
</root>

I want to remove the payload nodes that its localeId != "es" and translation!= "Type 1" using Groovy.

The result will be like this (only Doc1 and Doc4 are correct):

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <payload>
      <title>Doc1</title>
      <localizedTitle>
         <localeID>es</localeID>
         <translation>Type 1</translation>
      </localizedTitle>
      <localizedTitle>
         <localeID>en</localeID>
         <translation>Type 1</translation>
      </localizedTitle>
   </payload>
   <payload>
      <title>Doc4</title>
      <localizedTitle>
         <localeID>es</localeID>
         <translation>Type 1</translation>
      </localizedTitle>
      <localizedTitle>
         <localeID>en</localeID>
         <translation>Type 1</translation>
      </localizedTitle>
   </payload>
</root>

Solution

  • Please try the following XSLT.

    It is using a so called Identity Transform pattern.

    Input XML

    <?xml version="1.0" encoding="UTF-8"?>
    <root>
        <payload>
            <title>Doc1</title>
            <localizedTitle>
                <localeID>es</localeID>
                <translation>Type 1</translation>
            </localizedTitle>
            <localizedTitle>
                <localeID>en</localeID>
                <translation>Type 1</translation>
            </localizedTitle>
        </payload>
        <payload>
            <title>Doc3</title>
            <localizedTitle>
                <localeID>es</localeID>
                <translation>Type 3</translation>
            </localizedTitle>
            <localizedTitle>
                <localeID>en</localeID>
                <translation>Type 3</translation>
            </localizedTitle>
        </payload>
        <payload>
            <title>Doc4</title>
            <localizedTitle>
                <localeID>es</localeID>
                <translation>Type 1</translation>
            </localizedTitle>
            <localizedTitle>
                <localeID>en</localeID>
                <translation>Type 1</translation>
            </localizedTitle>
        </payload>
    </root>
    

    XSLT

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="no"/>
        <xsl:strip-space elements="*"/>
    
        <xsl:template match="node()|@*">
            <xsl:copy>
                <xsl:apply-templates select="node()|@*"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="payload[localizedTitle/localeID!='es' and not(localizedTitle/translation=('Type 1','Type 2'))]"/>
    </xsl:stylesheet>
    

    Output XML

    <?xml version='1.0' encoding='utf-8' ?>
    <root>
      <payload>
        <title>Doc1</title>
        <localizedTitle>
          <localeID>es</localeID>
          <translation>Type 1</translation>
        </localizedTitle>
        <localizedTitle>
          <localeID>en</localeID>
          <translation>Type 1</translation>
        </localizedTitle>
      </payload>
      <payload>
        <title>Doc4</title>
        <localizedTitle>
          <localeID>es</localeID>
          <translation>Type 1</translation>
        </localizedTitle>
        <localizedTitle>
          <localeID>en</localeID>
          <translation>Type 1</translation>
        </localizedTitle>
      </payload>
    </root>