fusio icon indicating copy to clipboard operation
fusio copied to clipboard

getbody in XML instead of JSON

Open mmaateurol opened this issue 4 years ago • 6 comments

@chriskapp I am creating a gateway action for an api that expects XML and returns XML.

For passing the body i need the body in XML. ( can be different XML ) ( using pasethrough ) But i can only get the body in JSON as described. Is there a way to get the original BODY. I have been digging through the src but cant find . Or do need convert the JSON back to XML.

The JSON body is missing the top level btw.

<Messages>
     <Message>
            <id>1</id>
            <title>a title</title> 
     </Message>
</Messages> 

is giving me

{
  "Message" : { 
         "id" : 1
         "title": "a title"
    } 
}

instead of

{ 
  "Messages" : {
        "Message" : { 
             "id" : 1
             "title": "a title"
         }
    } 
}

mmaateurol avatar Dec 02 '21 13:12 mmaateurol

Also if i want to rebuild the XML i have the problem that XML->jSON elements with preceding 0 are seen as integers instead of string.

<Messages>
     <Message>
            <id>1</id>
            <elementwithprecedingzero>00000011121</elementwithprecedingzero>
            <title>a title</title> 
     </Message>
</Messages> 
{ 
   "Message" : { 
             "id" : 1
              "elementwithprecedingzero" : 11121
             "title": "a title"
      }
} 

mmaateurol avatar Dec 03 '21 09:12 mmaateurol

Hi, so Fusio tries to parse your XML structure into an object structure which is similar to JSON because of this Fusio can also validate your XML input if you provide a request schema at a route and in general the complete system works with this structure. The XML parsing process is not perfect, if you like you can take a look at the XML transformer s. https://github.com/apioo/psx-data/blob/master/src/Transformer/XmlArray.php which builds the object structure based on the raw XML input.

chriskapp avatar Dec 09 '21 18:12 chriskapp

for also extracting rootElementname

Following change

    public function transform($data)
    {
        if (!$data instanceof DOMDocument) {
            throw new InvalidArgumentException('Data must be an instanceof DOMDocument');
        }

        $rootelement=$data->documentElement;
        $result = new \stdClass();
        $result->{$rootelement->nodeName}=$this->recToXml($data->documentElement);
        return $result;
    }

mmaateurol avatar Dec 10 '21 08:12 mmaateurol

and to assign String to numbers starting with 0

protected function parseValue($value)
    {
        if (is_numeric($value) &&  ( strlen($value)>1 && strncmp($value, "0", 1) != 0) ) {
            return strpos($value, '.') !== false ? (float) $value : (int) $value;
        } elseif ($value === 'true' || $value === '1') {
            return true;
        } elseif ($value === 'false' || $value === '0') {
            return false;
        } else {
            return $value;
        }
    }

mmaateurol avatar Dec 10 '21 08:12 mmaateurol

In PHPSandbox Action

    function is_assoc_array($array){
        if(is_array($array) !== true){
            return false;
        }else{

            $check = json_decode(json_encode($array));
    
            if(is_object($check) === true){
                return true;
            }else{
                return false;
            }
        }
    }

    /** 
     * Iterative XML constructor 
     * 
     * @param array $array 
     * @param object|boolean $xml 
     * @return string 
     */
     function array2xml( $array, $xml = false) {
        // Test if iteration
        if ( $xml === false ) {
          $key= key($array);     
          $xml = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8"?><'.$key.'/>');
          $array=$array[$key];
        }
        foreach( $array as $key => $value ) {
                // Another array? Iterate
                if ( is_array( $value ) ) {
                    if(!is_assoc_array($value)) {
                        foreach( $value as $skipkey => $childvalue )
                           array2xml( $childvalue, $xml->addChild( $key ) );     
                    }
                    else {
                        array2xml( $value, $xml->addChild( $key ) );
                    }
                } else {
                  $xml->addChild( $key, $value );
                }
            }                

        // Return XML
        return $xml->asXML();
    }

    // Get The transformed XML 
    $data= $request->getPayload();
    
    // Decode body (stdClass) to jSON to array 
    $jSON = json_decode(json_encode($data),true);
    
    // Process array elements to XML
    $xml = array2xml( $jSON, false );

mmaateurol avatar Dec 10 '21 11:12 mmaateurol

Hey @mmaateurol thanks for the suggestion, can you provide a PR at the https://github.com/apioo/psx-data repository containing this change. In general this is of course a huge BC since this changes the XML output of every endpoint but if you provide a PR we can talk about this change.

chriskapp avatar Dec 18 '21 13:12 chriskapp