0

I'm having some difficulties in changing XML Node values with PHP.

My XML is the following

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:xsd="http://www.w3.org/2001/XMLSchema"
      xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
      <soap:Body>
            <ProcessTransaction
                  xmlns="http://example.com">
                  <TransactionRequest
                        xmlns="http://example.com">
                        <Header>
                              <RequestType>SALE</RequestType>
                              <RequestMethod>SYNCHRONOUS</RequestMethod>
                              <MerchantInfo>
                                    <PosName>kwstasna</PosName>
                                    <PosID>1234</PosID>
                              </MerchantInfo>
                        </Header>
                  </TransactionRequest>
            </ProcessTransaction>
      </soap:Body>
</soap:Envelope> 

And i want to change PosName and PosID. The XML is received from a POST Request. If i print_r($REQUEST['xml'] I get the values in text.

And what i've tried is the following

$posid = '321';
$posname = 'nakwsta';

$result = $xml->xpath("/soap:Envelope/soap:Body/ProcessTransaction/TransactionRequest/Header/MerchantInfo");

$result[0]->PosID = $posid;
$result[0]->PosName = $posname;

echo $result;

But i get an empty array Array[]

I think my mistake is in the values of <soap:Envelope for example. Anyone that had the same issue and find out the way to solve it?

Thanks a lot for your time.

8
  • you have to register your namespace(s) to your $xml in order to get the right path (php.net/manual/en/simplexmlelement.registerxpathnamespace.php) Commented Dec 11, 2017 at 15:20
  • @Edwin at the first part that exist 3 namespaces what should i do? Commented Dec 11, 2017 at 15:26
  • you need to register your xmlns="http://example.com", because this is the node that you are trying to use (see first example in the manual) Commented Dec 11, 2017 at 15:28
  • What is your desired result? A transformed XML or just parsed XPath values? Commented Dec 11, 2017 at 15:30
  • @Edwin its the same as the answer below right? Commented Dec 11, 2017 at 15:33

2 Answers 2

4

The ProcessTransaction element (and all of its child nodes) are in the "http://example.com" namespace. If you want to access them using xpath(), you'll need to register a namespace prefix:

$xml->registerXPathNamespace('ex', 'http://example.com');

You can then use the ex prefix on all relevant parts of your query

$result = $xml->xpath("/soap:Envelope/soap:Body/ex:ProcessTransaction/ex:TransactionRequest/ex:Header/ex:MerchantInfo");

The rest of your code should function correctly, see https://eval.in/916856

Sign up to request clarification or add additional context in comments.

3 Comments

great answer and your example is correct, but is there any way to transform it back to xml ?
You should just be able to call $xml->asXML(), I'll update with a new example
100% correct. I didn't knew anything about namespaces. first time to grab an XML ! thank you so much !
2

Consider a parameterized XSLT (not unlike parameterized SQL) where PHP passes value to the underlying script with setParameter().

As information, XSLT (sibling to XPath) is a special-purpose language designed to transform XML files. PHP can run XSLT 1.0 scripts with the XSL class. Specifically, below runs the Identity Transform to copy XML as is and then rewrites the PosName and PosID nodes. Default namespace is handled accordingly in top root tag aligned to doc prefix.

XSLT (save as .xsl file, a special well-formed .xml file)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                              xmlns:doc="http://example.com">  
  <xsl:output method="xml" indent="yes" />
  <xsl:strip-space elements="*" />

  <xsl:param name="PosNameParam"/>
  <xsl:param name="PosIDParam"/>

  <!-- IDENTITY TRANSFORM -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- RE-WRITE PosName NODE -->
  <xsl:template match="doc:PosName">    
    <xsl:copy>
       <xsl:value-of select="$PosNameParam"/>
    </xsl:copy>
  </xsl:template>

  <!-- RE-WRITE PosID NODE -->
  <xsl:template match="doc:PosID">
    <xsl:copy>
        <xsl:value-of select="$PosIDParam"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

PHP

$posid = '321';
$posname = 'nakwsta';

// Load XML and XSL
$xml = new DOMDocument;
$xml->load('Input.xml');

$xsl = new DOMDocument;
$xsl->load('XSLTScript.xsl');

// Configure transformer
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl); 

// Assign values to XSLT parameters
$proc->setParameter('', 'PosNameParam', $posid);
$proc->setParameter('', 'PosIDParam', $posname);

// Transform XML source
$newXML = new DOMDocument;
$newXML = $proc->transformToXML($xml);

// Output to console
echo $newXML;

// Output to file
file_put_contents('Output.xml', $newXML);

Output

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
      <soap:Body>
            <ProcessTransaction xmlns="http://example.com">
                  <TransactionRequest>
                        <Header>
                              <RequestType>SALE</RequestType>
                              <RequestMethod>SYNCHRONOUS</RequestMethod>
                              <MerchantInfo>
                                    <PosName>nakwsta</PosName>
                                    <PosID>321</PosID>
                              </MerchantInfo>
                        </Header>
                  </TransactionRequest>
            </ProcessTransaction>
      </soap:Body>
</soap:Envelope>

2 Comments

this looks nice, but what's the advantage to do it like this? (thanks)
Right now it seems overkill since you are making small changes. But if you have to make substantial transformation like new nodes, flattening out children, convert to csv/txt, XSLT is a great tool as you avoid many foreach loops and if logic. Besides too I recently found out about passing parameters in PHP and Python, and just wanted to have fun with your question!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.