0

Portion of xml file that represents the problem (the xml file has hundreds of customers record)

    <?xml version="1.0" encoding="utf-8"?>
    <test>
       <customer>   
          <name>customer 1</name>
          <address>address 1</address>
          <city>city 1</city>
          <state>state 1</state>
          <zip>zip 1</zip>
          <phone>phone 1</phone>
          <buyerinfo>
             <shippingaddress>
               <name>ship to</name>
               <address>Ship address1</address>
             </shippingaddress>
           </buyerinfo>
           <shippingDetail>
             <saletax>
               <saletaxamount>2</saletaxamount>
             </saletax>
           </shippingDetail>
       </customer>...

Below is my code

 //Xml string is parsed and creates a DOM Document object
    $responseDoc = new DomDocument();        
    $responseDoc->load('test.xml');     
    foreach ($responseDoc->getElementsByTagName('customer') as $customer){

     $sSQL = sprintf(
    "INSERT INTO customer (name, address, city, state, zip, phone, shipto, shipadderss, tax) 
    VALUES ('%s','%s', '%s', '%s','%s','%s', '%s','%s','%s')",
    mysql_real_escape_string($customer->getElementsByTagName('name')->item(0)->nodeValue),
    mysql_real_escape_string($customer->getElementsByTagName('address')->item(0)->nodeValue),
    mysql_real_escape_string($customer->getElementsByTagName('city')->item(0)->nodeValue),
    mysql_real_escape_string($customer->getElementsByTagName('state')->item(0)->nodeValue),
    mysql_real_escape_string($customer->getElementsByTagName('zip')->item(0)->nodeValue),
    mysql_real_escape_string($customer->getElementsByTagName('phone')->item(0)->nodeValue)
    ?
    ?
    ?       
);
$rResult = mysql_query($sSQL);

if(mysql_errno() > 0)
{
    printf(
        '<h4 style="color: red;">Query Error:</h4>
        <p>(%s) - %s</p>
        <p>Query: %s</p>
        <hr />',
        mysql_errno(),
        mysql_error(),
        $sSQL
    );
}

    }

Questions:

  1. How do I get access to get customer.buyerinfo.shippingaddress.name node value using mysql_real_escape_string in my insert statement? indicated with "???"

    The fact that I have two nodes with the same node name "name", one is customer.name and another is customer.buyerinfo.shippingaddress.name to name make it problematic to use getElementsByTagName "name" tag to get the value.

  2. the same as the first one but how do I get saletaxamount node data value?

    Please kindly help. Thank you!

Jiǎng
  • 13
  • 2
  • 3
  • 1
    1. There is no `???` in your code. Any why are you making such an unholy mix of code? Extract your values from XML **THEN** build your query. mixing it together like that makes for an utterly unreadable useless mess. – Marc B Apr 12 '13 at 16:56
  • @ Marc B. Thank you for your kind feedback. I meant to say "???" in my insert statement. Learn something from you "Utterly unreadable useless mess". WoW! Thank you for that. – Jiǎng Apr 12 '13 at 17:13

2 Answers2

1

For the XML data you have I would prefer the SimpleXML extension, it ships with everything you need and it's not that much code to write (it is DOMDocument's little sister).

So for each customer in the input data, you want to fetch your 9 or so values. You can formulate those values as an xpath:

$values = <<<XPATH
(
    name
    |address
    |city
    |state
    |zip
    |phone
    |buyerinfo/shippingaddress/name
    |buyerinfo/shippingaddress/address
    |shippingDetail/saletax/saletaxamount
)
XPATH;

This works similar to as with a database query. You create a string that contains the query, for XML in the Xpath language.

And we do same for SQL as both should go hand-in-hand together, so here is is the according SQL pattern:

$pattern = <<<SQL
INSERT INTO customer
  (
    name, address, city, state, zip, phone, shipto, shipadderss, tax
  )
  VALUES
  (
    '%s','%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s'
  )
SQL;

All this needs now is to open the XML and specify the customer elements to work on:

$customers = simplexml_load_string($test)->customer; // "test.xml"

Then you only need to foreach over each customer, obtain the values, escape them, insert them into the query and run the SQL query (or create one larger query containing more than one record):

foreach ($customers as $customer) 
{
    $data = $customer->xpath($values);
    $escaped = array_map('mysql_real_escape_string', $data);
    $query = vsprintf($pattern, $escaped);

    // you can now run the query now
    // ...
}

Yes, that is your code already. As you can see, Making use of arrays, xpath and SQL, you can simplify this to a great extend.

For the first customer in your sample-XML this then generates the following query:

INSERT INTO customer
  (
    name, address, city, state, zip, phone, shipto, shipadderss, tax
  )
  VALUES
  (
    'customer 1','address 1', 'city 1', 'state 1', 'zip 1', 'phone 1', 'ship to', 'Ship address1', '2'
  )

The whole code-example:

$values = <<<XPATH
(
    name
    |address
    |city
    |state
    |zip
    |phone
    |buyerinfo/shippingaddress/name
    |buyerinfo/shippingaddress/address
    |shippingDetail/saletax/saletaxamount
)
XPATH;

$pattern = <<<SQL
INSERT INTO customer
  (
    name, address, city, state, zip, phone, shipto, shipadderss, tax
  )
  VALUES
  (
    '%s','%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s'
  )
SQL;

$customers = simplexml_load_string($test)->customer; // "test.xml"

foreach ($customers as $customer)
{
    $data = $customer->xpath($values);
    $escaped = array_map('mysql_real_escape_string', $data);
    $query = vsprintf($pattern, $escaped);

    // you can now run the query now
    $result = mysql_query($query);
    if(mysql_errno())
    {
        printf(
            '<h4 style="color: red;">Query Error:</h4>
            <p>(%s) - %s</p>
            <p>Query:
              <pre>%s</pre>
            </p>
            <hr />',
            mysql_errno(),
            htmlspecialchars(mysql_error()),
            htmlspecialchars($query)
        );
    }
}
M8R-1jmw5r
  • 4,896
  • 2
  • 18
  • 26
  • @ M8R-1jmw5r Thank you for your feedback.Above is just an example portion of the project that I was working on. It seems like xpath is a good idea for flattening out a complex xml tree. I will give it a shot and see what happens. Thank you again for your time and guidance. – Jiǎng Apr 12 '13 at 21:05
  • Yes I would really prefer Xpath if you need to traverse on different depth (and also if it differs between element-values and attribute-values). – M8R-1jmw5r Apr 12 '13 at 21:38
  • @ M8R-1jmw5r This is looking good. I have a question. Tested it and it worked fine until I ran into non-existing nodes. how do I check if a node exist, if exist, insert the value else set a default value? Example is tax node. for some customer it is not applicable. Thus xml does not return tax node at all. Please help. Thank you. – Jiǎng Apr 13 '13 at 21:25
  • Just seeing your comment now. For this answer, it is a pre-condition that always all exist per each node. At least for the simplified form given here. If you wrap functionality into objects, you can deal with a higher level of detail, e.g. providing default values for certain properties. See this other related answer of mine: [Extracting data from HTML using PHP and xPath](http://stackoverflow.com/a/15982272/2261774) that can represent the data in objects which allows more control. – M8R-1jmw5r Apr 15 '13 at 23:33
  • Sorry to necro and old thread but im looking at this now and im wondering what is the contents of the variable $test? Is it the url of your xml file? You haven't specified this in the code example? – David Folksman Jun 12 '13 at 10:28
  • I also get invalid argument supplied at foreach ($customers as $customer) – David Folksman Jun 12 '13 at 10:37
0

you can get child node value with a loop inside shippingaddress node.

Something like, after mysql_real_escape_string($customer->getElementsByTagName('phone')->item(0)->nodeValue)

add:

foreach ($customer->getElementsByTagName('buyerinfo') as $buyerinfo)
{
    foreach ($buyerinfo->getElementsByTagName('shippingaddress') as $shippingaddress)
    {
        mysql_real_escape_string($shippingaddress->getElementsByTagName('name')->item(0)->nodeValue),
        mysql_real_escape_string($shippingaddress->getElementsByTagName('address')->item(0)->nodeValue)
    }
}

of course you will have to fix query with new values.

this should your job, sorry i haven't a chance to test it

Fabio
  • 23,183
  • 12
  • 55
  • 64
  • Thank you for the feedback. Would you please elaborate on fixing the query with new values? code example would be highly appreciated. Thank you again for your time, energy and effort in helping to solve this problem. – Jiǎng Apr 12 '13 at 20:58