0

I have one field $xml that contains some XML value. First I must mention that elements are not seperated each in new line (row) but they are bounded together like a String without new lines.

I will first display XML structure how it looks to be easily "readable".

<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv=" http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
        <p:queryBillingAccountResponse xmlns:p=" http://www.ibm.com">
            <ns0:customerAccount xmlns:ns0=" http://www.ibm.com/xmlns/">
                <AccountStatus>Paid</AccountStatus>
                <ComponentCustomerAccount>
                    <Name>ADSL 4</Name>
                    <CharacteristicValue>
                        <Characteristic>
                            <Name>Balance</Name>
                        </Characteristic>
                        <Value>0.0</Value>
                    </CharacteristicValue>
                    <AccountStatus>Paid</AccountStatus>
                </ComponentCustomerAccount>
            </ns0:customerAccount>
        </p:queryBillingAccountResponse>
    </soapenv:Body>
</soapenv:Envelope>
<AccountStatus>Paid</AccountStatus>
</ComponentCustomerAccount>
</ns0:customerAccount>
</p:queryBillingAccountResponse>
</soapenv:Body>
</soapenv:Envelope>

but I again I must mention that real value in $xml field is not so easily readable. On example it looks like this

<?xml version="1.0" encoding="utf-8"?><soapenv:Envelope xmlns:soapenv=" http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><p:queryBillingAccountResponse xmlns:p=" http://www.ibm.com">.......

I want to delete elements : ?xmlversion soapenv:Envelope and soapenv:Body along with their attributes. I want to delete them on the beggining and on the end of xml value. Everything else stays as it is1 How to achive this? So my new value in php field should start from queryBillingAccountResponse element. thank you

Stefke
  • 141
  • 8
  • 19

3 Answers3

2

For valid XML you can use SimpeXML or DOMDocument to query the child nodes of the body element.

$xml = '<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
        <p:queryBillingAccountResponse xmlns:p="http://www.ibm.com">
            <ns0:customerAccount xmlns:ns0="http://www.ibm.com/xmlns/">
                <AccountStatus>Paid</AccountStatus>
                <ComponentCustomerAccount>
                    <Name>ADSL 4</Name>
                    <CharacteristicValue>
                        <Characteristic>
                            <Name>Balance</Name>
                        </Characteristic>
                        <Value>0.0</Value>
                    </CharacteristicValue>
                    <AccountStatus>Paid</AccountStatus>
                </ComponentCustomerAccount>
            </ns0:customerAccount>
        </p:queryBillingAccountResponse>
    </soapenv:Body>
</soapenv:Envelope>';

$xml = simplexml_load_string($xml);
$xml = $xml->xpath('//soapenv:Body/child::*')[0];
echo $xml->asXML();

The result is:

<p:queryBillingAccountResponse xmlns:p="http://www.ibm.com">
    <ns0:customerAccount xmlns:ns0="http://www.ibm.com/xmlns/">
        <AccountStatus>Paid</AccountStatus>
        <ComponentCustomerAccount>
            <Name>ADSL 4</Name>
            <CharacteristicValue>
                <Characteristic>
                    <Name>Balance</Name>
                </Characteristic>
                <Value>0.0</Value>
            </CharacteristicValue>
            <AccountStatus>Paid</AccountStatus>
        </ComponentCustomerAccount>
    </ns0:customerAccount>
</p:queryBillingAccountResponse>

But the problem is that your XML isn't valid and I don't know if it's a copy and paste error.

akkie
  • 2,523
  • 1
  • 20
  • 34
  • thanks for answe. why do you think it is not vaid maybe I do not see some parsing error? shoudl I instatiate this $xml = simplexml_load_string($xml); with new simplexmlelement ??? – Stefke Mar 22 '13 at 09:27
  • Your XML isn't valid because it contains extra content at the end of the closing tag. Furthermore a space before a namespace URL isnt valid. What do you mean with: shoudl I instatiate this $xml = simplexml_load_string($xml); with new simplexmlelement – akkie Mar 22 '13 at 10:00
  • this is a string field that contains xml value so I meant shoul I inititate it woth new simplexmlelement before I could use some other functions to parse further that xml. (on example I will need later foreach fucntion to parse it further). So my question is will this be enough simplexml_load_string($xml); to make xml format in that string field? thank you – Stefke Mar 22 '13 at 10:31
  • The function `simplexml_load_string` returns a `SimpleXMLElement` instance. Now with this instance you can traverse your XML. So the first step should be: Create a `SimpleXMLElement` instance from your XML string. Then select the child nodes of the body with xpath, as I described in my example. `$xml->xpath('//soapenv:Body/child::*')` gives you a array of `SimpleXMLElement` instances. So you can iterate over these instances to do further processing of your XML. – akkie Mar 22 '13 at 10:54
  • after $xml = simplexml_load_string($xml); $xml is emptty. is this becaue of unvalid XML - how to change it after retrieviel to be valid/ thank you – Stefke Mar 23 '13 at 10:09
1

This is easiest and the most foolproof with XSLT:

function extract_body_stripns($xmlstring) {
    static $xsl = NULL;
    if ($xsl === NULL) {
        $xsl_soap_body_nons = <<<'EOT'
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"
  xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output encoding="UTF-8" method="xml" />

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

  <xsl:template match="*[namespace-uri()]" priority="1">
    <xsl:element name="{local-name()}">
      <xsl:apply-templates select="@*|node()"/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="@*[namespace-uri()]" priority="1">
    <xsl:attribute name="{local-name()}">
      <xsl:value-of select="."/>
    </xsl:attribute>
  </xsl:template>

  <xsl:template match="/">
    <xsl:apply-templates select="/soapenv:Envelope/soapenv:Body/*"/>
  </xsl:template>
</xsl:stylesheet>
EOT;

        $style = new DOMDocument();
        $style->loadXML($xsl_soap_body_nons, LIBXML_COMPACT | LIBXML_NOBLANKS | LIBXML_NONET);
        $xsl = new XSLTProcessor();
        $xsl->importStylesheet($style);
        unset($style);
    }
    $d = new DOMDocument();
    $d->loadXML($xmlstring, LIBXML_COMPACT | LIBXML_NONET);
    $newd = $xsl->transformToDoc($d);
    unset($d);
    return $newd->saveXML($newd->documentElement);
}

Using this function:

echo extract_body_stripns($xmlString);

Result is:

<queryBillingAccountResponse>
        <customerAccount>
            <ComponentCustomerAccount>
                <Name>ADSL 4</Name>
                <CharacteristicValue>
                    <Characteristic>
                        <Name>Balance</Name>
                    </Characteristic>
                    <Value>0.0</Value>
                </CharacteristicValue>
                <AccountStatus>Paid</AccountStatus>
            </ComponentCustomerAccount>
        </customerAccount>
    </queryBillingAccountResponse>

Note that if you ever have namespaced attributes in your source document, the process of stripping namespaces may cause you to lose some of them. E.g. with the element <myelement ns:myattrib="a" myattrib="b"/>, one of your attributes will be lost, and which one you will lose is not consistent!

Francis Avila
  • 31,233
  • 6
  • 58
  • 96
  • hello thank you for answer but I do not want this attributes in final xml..ADSL 4 can we implement something which will now show us attributes in elements like in your example for ADSL 4. thank you – Stefke Mar 23 '13 at 15:27
  • That is an attribute I added to your xml to test the attribute handling code and forgot to remove. If you actually run this code on your machine with your xml, you will see no attributes are added. – Francis Avila Mar 23 '13 at 16:37
-1

You can use ereg_replace http://php.net/manual/en/function.ereg-replace.php

Using regex to identify elements you want to delete.

Ajouve
  • 9,735
  • 26
  • 90
  • 137
  • `ereg_` functions have been _deprecated_ since PHP 5.3, but even more important using regexes for html/xml parsing [that way madness lies....](http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454). – Wrikken Mar 22 '13 at 09:06