Get specific node in xml?

只愿长相守 提交于 2019-12-06 11:02:14

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.


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 );

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