Jump to content

Merge XML files via PHP


Billy-3k

Recommended Posts

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.

Link to comment
Share on other sites

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

  • Like 1
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

  • Like 1
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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>

***************************************************************/

  • Great Answer 1
Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.