Billy-3k Posted September 3, 2019 Share Posted September 3, 2019 Hello, I've created a PHP file to merge XML files by ReferenceID(product_print_id) but i don't get the result that i want. I think i must use cloneNode and DOMNode::insertBefore but I think i'm lost. The first file is prodInfo.xml: <?xml version="1.0" encoding="utf-8"?> <PRODUCTINFORMATION> <PRODUCTS> <PRODUCT> <PRODUCT_NUMBER>53-03</PRODUCT_NUMBER> <PRODUCT_PRINT_ID>42</PRODUCT_PRINT_ID> <PRODUCT_NAME>ProductFirst</PRODUCT_NAME> <COLOR_CODE>03</COLOR_CODE> </PRODUCT> </PRODUCTS> </PRODUCTINFORMATION> and the second file is printInfo.xml: <?xml version="1.0" encoding="utf-8"?> <PRINTINGINFORMATION> <PRODUCTS> <PRODUCT> <PRODUCT_PRINT_ID>42</PRODUCT_PRINT_ID> <PRINTING_POSITIONS> <PRINTING_POSITION> <ID>TOP BOX</ID> <PRINTING_TECHNIQUE> <ID>DL</ID> </PRINTING_TECHNIQUE> <PRINTING_TECHNIQUE> <ID>L2</ID> </PRINTING_TECHNIQUE> <PRINTING_TECHNIQUE> <ID>P4</ID> </PRINTING_TECHNIQUE> </PRINTING_POSITION> </PRINTING_POSITIONS> </PRODUCT> </PRODUCTS> </PRINTINGINFORMATION> The php file i created is the following: <?php header ("Content-Type:text/xml"); $target = new DOMDocument(); $target->preserveWhiteSpace = FALSE; $target->load('prodInfo.xml'); $targetXpath = new DOMXpath($target); $source = new DOMDocument(); $source->load('printInfo.xml'); $sourceXpath = new DOMXpath($source); foreach ($targetXpath->evaluate('//PRODUCT') as $PRODUCTNode) { $PRODUCT_PRINT_ID = $targetXpath->evaluate('string(PRODUCT_PRINT_ID)', $PRODUCTNode); foreach ($sourceXpath->evaluate('//PRODUCT[PRODUCT_PRINT_ID="'.$PRODUCT_PRINT_ID.'"]/*[not(self::PRODUCT_PRINT_ID)]') as $node) { $PRODUCTNode->appendChild( $target->importNode($node, TRUE) ); } } $target->formatOutput = TRUE; echo $target->saveXml(); ?> The output/result i get is this: <?xml version="1.0" encoding="utf-8"?> <PRODUCTINFORMATION> <PRODUCTS> <PRODUCT> <PRODUCT_NUMBER>53-03</PRODUCT_NUMBER> <PRODUCT_PRINT_ID>42</PRODUCT_PRINT_ID> <PRODUCT_NAME>ProductFirst</PRODUCT_NAME> <COLOR_CODE>03</COLOR_CODE> <PRINTING_POSITIONS> <PRINTING_POSITION> <ID>TOP BOX</ID> <PRINTING_TECHNIQUE> <ID>DL</ID> </PRINTING_TECHNIQUE> <PRINTING_TECHNIQUE> <ID>L2</ID> </PRINTING_TECHNIQUE> <PRINTING_TECHNIQUE> <ID>P4</ID> </PRINTING_TECHNIQUE> </PRINTING_POSITION> </PRINTING_POSITIONS> </PRODUCT> </PRODUCTS> </PRODUCTINFORMATION> But what i want to achieve is this: <?xml version="1.0" encoding="utf-8"?> <PRODUCTINFORMATION> <PRODUCTS> <PRODUCT> <PRODUCT_NUMBER>53-03</PRODUCT_NUMBER> <PRODUCT_PRINT_ID>42</PRODUCT_PRINT_ID> <PRODUCT_NAME>ProductFirst</PRODUCT_NAME> <PRINTING_POSITIONS> <PRINTING_POSITION> <ID>TOP BOX</ID> <PRINTING_TECHNIQUE> <ID>DL</ID> </PRINTING_TECHNIQUE> <COLOR_CODE>03</COLOR_CODE> </PRINTING_POSITION> <PRINTING_POSITION> <ID>TOP BOX</ID> <PRINTING_TECHNIQUE> <ID>L2</ID> </PRINTING_TECHNIQUE> <COLOR_CODE>03</COLOR_CODE> </PRINTING_POSITION> <PRINTING_POSITION> <ID>TOP BOX</ID> <PRINTING_TECHNIQUE> <ID>P4</ID> </PRINTING_TECHNIQUE> <COLOR_CODE>03</COLOR_CODE> </PRINTING_POSITION> </PRINTING_POSITIONS> </PRODUCT> </PRODUCTS> </PRODUCTINFORMATION> So as you can see i want to repeat the field PRINTING POSITION ID for every PRINTING TECHNIQUE and also i want to repeat the field COLOR CODE for every PRINTING POSITION. Anyone can help me with this? Thanks in advance. Quote Link to comment Share on other sites More sharing options...
requinix Posted September 3, 2019 Share Posted September 3, 2019 It's quite happily copying what you've told it to copy. Without any changes. Thing is you don't want to just copy the nodes. What you want is to change the structure of the XML. Which means you have to write code that understands the original structures and the structures you're trying to create. 1. Copy the PRODUCT_NUMBER, PRODUCT_PRINT_ID, PRODUCT_NAME 2. Create a new PRINTING_POSITIONS to work on. For each PRINTING_POSITION, 3. Create a new PRINTING_POSITION to work on. For each PRINTING_TECHNIQUE, 4. Copy the ID 5. Copy the PRINTING_TECHNIQUE 6. Either (a) copy the COLOR_CODE or (b) copy everything except the PRODUCT_NUMBER, PRINT_ID, and NAME 1 Quote Link to comment Share on other sites More sharing options...
Billy-3k Posted September 3, 2019 Author Share Posted September 3, 2019 Thank you for your reply! I guess i must use cloneNode to clone COLOR_CODE and insertBefore to place it where i want, right? Or is there an easier way to achieve that? It sounds a lot of work and kinda hard for me and i'm wondering if it's better to start over with XSLT. Quote Link to comment Share on other sites More sharing options...
requinix Posted September 3, 2019 Share Posted September 3, 2019 20 minutes ago, Billy-3k said: I guess i must use cloneNode to clone COLOR_CODE and insertBefore to place it where i want, right? Or is there an easier way to achieve that? I believe you can keep using importNode, it's just that you have to be deliberate about what you copy and where you appendChild it to. Can't just do a simple copy and expect it to transform itself into the shape you want. 20 minutes ago, Billy-3k said: It sounds a lot of work and kinda hard for me and i'm wondering if it's better to start over with XSLT. But then you'd have to learn XSLT, and then figure out how to make PHP do it. 1 Quote Link to comment Share on other sites More sharing options...
Billy-3k Posted September 3, 2019 Author Share Posted September 3, 2019 I'm new to this and I never tried to change structure of XML files, that's why it sounds hard. I'm still trying to understand how this works! Thanks for your help, I'll try to import nodes one by one as you said and I'll get back! Quote Link to comment Share on other sites More sharing options...
requinix Posted September 3, 2019 Share Posted September 3, 2019 Try writing out explicit importNode/appendChild calls using the exact XMLs you showed. No loops, no trying to automatically find all nodes, I mean hardcode every call for each individual node. Get it to the point where it produces the output you want. Then look at the code and see what it looks like as a whole. Like, if you repeat the same couple calls for PRINTING_POSITION stuff three times, that means it should probably be a loop. Quote Link to comment Share on other sites More sharing options...
Barand Posted September 4, 2019 Share Posted September 4, 2019 My 0.02 worth... Why are you "denormalizing" your data by creating several objects all with the same id and color code. Would it not be more sensible (and a lot easier) to create a merged data set like this... <PRODUCTINFORMATION> <PRODUCTS> <PRODUCT> <PRODUCT_NUMBER>53-03</PRODUCT_NUMBER> <PRODUCT_PRINT_ID>42</PRODUCT_PRINT_ID> <PRODUCT_NAME>ProductFirst</PRODUCT_NAME> <COLOR_CODE>03</COLOR_CODE> <PRINTING_POSITION> <ID>TOP BOX</ID> </PRINTING_POSITION> <PRINTING_TECHNIQUES> <PRINTING_TECHNIQUE> <ID>DL</ID> </PRINTING_TECHNIQUE> <PRINTING_TECHNIQUE> <ID>L2</ID> </PRINTING_TECHNIQUE> <PRINTING_TECHNIQUE> <ID>P4</ID> </PRINTING_TECHNIQUE> </PRINTING_TECHNIQUES> </PRODUCT> </PRODUCTS> </PRODUCTINFORMATION> Below is my solution to your original quest using SimpleXML. Hava a go at it on your own as requinix suggested first then peek only if you really get stuck $xmlA = simplexml_load_file('A.xml'); // product info $xmlB = simplexml_load_file('B.xml'); // printing info // create empty output xml object $xmlC = new simpleXMLElement("<PRODUCTINFORMATION> </PRODUCTINFORMATION>"); $products = $xmlC->addChild("PRODUCTS"); // process file A foreach ($xmlA->PRODUCTS->PRODUCT as $proda) { $prodno = (string)$proda->PRODUCT_NUMBER; $prtid = (string)$proda->PRODUCT_PRINT_ID; $prodname = (string)$proda->PRODUCT_NAME; $color = (string)$proda->COLOR_CODE; // find related print info xml from xml file B based on PRODUCT_PRINT_ID $prodarr = $xmlB->xpath("PRODUCTS/PRODUCT[PRODUCT_PRINT_ID='$prtid']"); $prodb = $prodarr[0]; $prtposid = (string)$prodb->PRINTING_POSITIONS->PRINTING_POSITION->ID; // build the output xml $prodnew = $products->addChild('PRODUCT'); $prodnew->addChild('PRODUCT_NUMBER', $prodno); $prodnew->addChild('PRODUCT_PRINT_ID', $prtid); $prodnew->addChild('PRODUCT_NAME', $prodname); $prtposns = $prodnew->addChild('PRINTING_POSITIONS'); foreach ($prodb->PRINTING_POSITIONS->PRINTING_POSITION->PRINTING_TECHNIQUE as $tech) { $posnew = $prtposns->addChild('PRINTING_POSTION'); $posnew->addChild('ID', $prtposid); $postech = $posnew->addChild('PRINTING_TECHNIQUE'); $postech->addChild('ID', (string)$tech->ID); $posnew->addChild('COLOR_CODE', $color); } } file_put_contents('C.xml', $xmlC->asXML() ); // write output to file C /* C.XML produced by above code ****************************** <PRODUCTINFORMATION> <PRODUCTS> <PRODUCT> <PRODUCT_NUMBER>53-03</PRODUCT_NUMBER> <PRODUCT_PRINT_ID>42</PRODUCT_PRINT_ID> <PRODUCT_NAME>ProductFirst</PRODUCT_NAME> <PRINTING_POSITIONS> <PRINTING_POSTION> <ID>TOP BOX</ID> <PRINTING_TECHNIQUE> <ID>DL</ID> </PRINTING_TECHNIQUE> <COLOR_CODE>03</COLOR_CODE> </PRINTING_POSTION> <PRINTING_POSTION> <ID>TOP BOX</ID> <PRINTING_TECHNIQUE> <ID>L2</ID> </PRINTING_TECHNIQUE> <COLOR_CODE>03</COLOR_CODE> </PRINTING_POSTION> <PRINTING_POSTION> <ID>TOP BOX</ID> <PRINTING_TECHNIQUE> <ID>P4</ID> </PRINTING_TECHNIQUE> <COLOR_CODE>03</COLOR_CODE> </PRINTING_POSTION> </PRINTING_POSITIONS> </PRODUCT> </PRODUCTS> </PRODUCTINFORMATION> ***************************************************************/ 1 Quote Link to comment Share on other sites More sharing options...
Billy-3k Posted September 4, 2019 Author Share Posted September 4, 2019 Thank you very much for your help! I agree it's more sensible and a lot easier but i need this very particular structure that I wrote because it's the only way to import successfully the data using a plugin in Wordpress... Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.