Get specific node in xml?

喜你入骨 提交于 2019-12-07 18:48:43

问题


my xml is structured as follow:

<?xml version="1.0" ?>
<users>
    <user>
        <name>
            foo
        </name>
        <token>
            jfhsjfhksdjfhsjkfhksjfsdk
        </token>
        <connection>
            <host>
                localhost
            </host>
            <username>
                root
            </username>
            <dbName>
                Test
            </dbName>
            <dbPass>
                123456789
            </dbPass>
        </connection>
    </user>
    <user>
        ... same structure...
    </user>
</users>

I made this code that iterate through all xml node:

function getConString($node)
{
   $item = file_get_contents($_SERVER['DOCUMENT_ROOT'] . "con");
   $nodes = new SimpleXMLElement($item);
   $result = $nodes[0];

   foreach($result as $item => $value)
   {
      if($item == "token")
      {
         return $value->__toString();
     }
   }
}

what I'm trying to achieve is that when $node is equal to:

jfhsjfhksdjfhsjkfhksjfsdk

the connection node is returned as array, how I can achieve this?

UPDATE:

For someone that doesn't have understood, simply I want that if I insert the token: jfhsjfhksdjfhsjkfhksjfsdk the connection of the user with the token jfhsjfhksdjfhsjkfhksjfsdk will be returned. So in this case I want get all the content of connection node and create a connection string:

<connection>
            <host>
                localhost
            </host>
            <username>
                root
            </username>
            <dbName>
                Test
            </dbName>
            <dbPass>
                123456789
            </dbPass>
        </connection>

回答1:


First of all, some considerations about your XML code. I don't know if your real XML is formatted exactly as above, but if is it, it's important to highlight that XML whitespaces behavior is different from HTML: usually without DTD or XML schema definition, all whitespaces are significant whitespaces and should be preserved. Also with DTD or XML schema definitions, the whitespaces in the content are significant.

This means that with this XML:

<token>
    jfhsjfhksdjfhsjkfhksjfsdk
</token>

the <token> assume the value '\n jfhsjfhksdjfhsjkfhksjfsdk\n' (\n = line break) instead of 'jfhsjfhksdjfhsjkfhksjfsdk'.

This makes it difficult find the token using xPath without pre-modify the xml (you can use regex for it). You can use the contains() xPath syntax for this, but (theoretically) it can return more than one result.

I don't know if you have tested your code above, but also in that $value->__toString() return something like '\n jfhsjfhksdjfhsjkfhksjfsdk\n' (it can change depending of indentation level). To return only the token value, you have to change your code in:

return trim( $value->__toString() );

My advice is to change anyway your XML in this way:

<user>
    <name>foo</name>
    <token>jfhsjfhksdjfhsjkfhksjfsdk</token>
    <connection>
        <host>localhost</host>
        <username>root</username>
        <dbName>Test</dbName>
        <dbPass>123456789</dbPass>
    </connection>
</user>

because this is the most correct way to store data: if the XML is produced by you, change it should not be too difficult.

Anyway, I propose you two different functions - one with xPath, one without.

Function 1 (xPath) works only with modified XML:

function getConString( $token )
{
    $data = file_get_contents($_SERVER['DOCUMENT_ROOT'] . "con");
    $xml = new SimpleXMLElement( $data );

    $path = '//users/user/token[text()="'.$token.'"]';
    $found = $xml->xpath( $path );
    if( ! count( $found ) ) return False;

    $node = $found[0]->xpath('parent::*')[0];
    return (array) $node->connection;
}

Function 2, works with old and new XML:

function getConString( $token )
{
    $data = file_get_contents($_SERVER['DOCUMENT_ROOT'] . "con");
    $xml = new SimpleXMLElement( $data );

    foreach( $xml->user as $user )
    {
        if( trim($user->token->__toString()) == $token )
        {
            $retval = array();
            foreach( $user->connection[0] as $key => $val )
            { $retval[$key] = trim($val); }
            return $retval;
        }
    }

    return False;
}

Edit:

In the comments, you ask: “is possible take the connection node such as host, dbName ect... separate and save it in a specific variable”?

I do not understand what problems they can create this syntax:

$user = getConString( 'jfhsjfhksdjfhsjkfhksjfsdk' );
mysqli_connect ( $user['host'], $user['username'], $user['dbPass'], $user['dbName'] );

BTW, you can put returned value in separate variables in this way:

$user = getConString( 'jfhsjfhksdjfhsjkfhksjfsdk' );
foreach( $user as $key => $val ) $$key = $val;
mysqli_connect ( $host, $username, $dbPass, $dbName );

or - if you want specific variable names - change the 2nd function above in this way:

(...)
$retval = array();
foreach( $user->connection[0] as $key => $val )
{ $retval[] = trim($val); }
(...)

and then call it in this way:

list( $dbHost, $dbUser, $dbDb, $dbPass ) = getConString( 'jfhsjfhksdjfhsjkfhksjfsdk' );
mysqli_connect ( $dbHost, $dbUser, $dbPass, $dbDb );

You can change the variable names inside list with your preferred names. The function modification is necessary because list doesn't work with associative arrays.


  • See more about Whitespace in XML
  • See more about list() constructor



回答2:


Assuming you are not averse to using DOMDocument rather than simpleXML then you should be able to make use of the following. If not and you must use simpleXML the XPath query could be ported over for use with simplexml->xpath

$strxml='<?xml version="1.0" ?>
<users>
    <user>
        <name>
            foo
        </name>
        <token>
            jfhsjfhksdjfhsjkfhksjfsdk
        </token>
        <connection>
            <host>
                localhost
            </host>
            <username>
                root
            </username>
            <dbName>
                Test
            </dbName>
            <dbPass>
                123456789
            </dbPass>
        </connection>
    </user>
    <user>
        ... same structure...
    </user>
</users>';


/* an array to store details of connection */
$conndetails=array();
/* The particular value to be searched for in token nodes */
$var='jfhsjfhksdjfhsjkfhksjfsdk';


/* create the DOM objects & load xml source */
$dom=new DOMDocument;
$dom->loadXML( $strxml );
$xp=new DOMXPath( $dom );

/* Run the query to find the token with particular value - then it's next sibling */
$results=$xp->query('//token[contains( text(), "'.$var.'" )]/following-sibling::connection');

if( $results ){/* iterate through childnodes and store details in array */
    foreach( $results as $node ) {
        foreach( $node->childNodes as $child ) if( $child->nodeType==XML_ELEMENT_NODE ) $conndetails[ $child->tagName ]=$child->nodeValue;
    }
}

print_r( $conndetails );



回答3:


You can make one of these options into a function, but you should be able to understand how to do it, seeing this code. This will show you how to retrieve the information you want.

Option 1:

# using iteration
$data = new SimpleXMLElement($xml);
foreach ($data->item as $item){
    if ($item->user->token == 'jfhsjfhksdjfhsjkfhksjfsdk')
    {
        echo "host: " . $item->user->connection->host . "<br />";
        echo "username: " . $item->user->connection->username . "<br />";
        echo "dbName: " . $item->user->connection->dbName . "<br />";
        echo "dbPass: " . $item->user->connection->dbPass . "<br />";
    } else { continue; }
}

Option 2:

# using xpath
$data = new SimpleXMLElement($xml);
// Here we find the element token = jfhsjfhksdjfhsjkfhksjfsdk and get it's parent
$nodes = $data->xpath('//users/user/token[.="jfhsjfhksdjfhsjkfhksjfsdk"]/parent::*');
$user = $nodes[0];
echo "host: " . $user->connection->host . "<br />";
echo "username: " . $user->connection->username . "<br />";
echo "dbName: " . $user->connection->dbName . "<br />";
echo "dbPass: " . $user->connection->dbPass . "<br />";


来源:https://stackoverflow.com/questions/35242420/get-specific-node-in-xml

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!