获取 xml 中的特定节点?
Get specific node in xml?
我的xml结构如下:
<?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>
我编写了遍历所有 xml 节点的代码:
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();
}
}
}
我想要实现的是当 $node 等于:
jfhsjfhksdjfhsjkfhksjfsdk
连接节点以数组形式返回,我该如何实现?
更新:
对于不理解的人,我只是希望如果我插入令牌:jfhsjfhksdjfhsjkfhksjfsdk
将返回用户与令牌 jfhsjfhksdjfhsjkfhksjfsdk
的连接。所以在这种情况下,我想获取 connection
节点的所有内容并创建一个连接字符串:
<connection>
<host>
localhost
</host>
<username>
root
</username>
<dbName>
Test
</dbName>
<dbPass>
123456789
</dbPass>
</connection>
假设您不反对使用 DOMDocument
而不是 simpleXML
那么您应该可以使用以下内容。如果不是,您必须使用 simpleXML
XPath 查询可以移植到 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 );
您可以将这些选项之一变成一个函数,但您应该能够理解如何去做,看看这段代码。这将向您展示如何检索您想要的信息。
选项 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; }
}
选项 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 />";
首先,关于您的 XML 代码的一些注意事项。我不知道你真正的 XML 是否完全按照上面的格式,但如果是,重要的是要强调 XML 空格行为不同于 HTML:通常没有 DTD 或 XML 模式定义,所有空格都是重要的空格,应该保留。同样对于 DTD 或 XML 模式定义,内容中的空格很重要。
这意味着 XML:
<token>
jfhsjfhksdjfhsjkfhksjfsdk
</token>
<token>
假定值 '\n jfhsjfhksdjfhsjkfhksjfsdk\n'
(\n = 换行符)而不是 'jfhsjfhksdjfhsjkfhksjfsdk'
。
这使得在不预先修改 xml 的情况下使用 xPath 很难找到令牌(您可以使用正则表达式)。您可以为此使用 contains()
xPath 语法,但(理论上)它可以 return 多个结果。
我不知道你是否测试过上面的代码,还有 $value->__toString()
return 类似 '\n jfhsjfhksdjfhsjkfhksjfsdk\n'
的东西(它可以根据缩进级别而改变)。要 return 只有令牌值,您必须更改您的代码:
return trim( $value->__toString() );
我的建议是无论如何改变你的XML:
<user>
<name>foo</name>
<token>jfhsjfhksdjfhsjkfhksjfsdk</token>
<connection>
<host>localhost</host>
<username>root</username>
<dbName>Test</dbName>
<dbPass>123456789</dbPass>
</connection>
</user>
因为这是最正确的数据存储方式:如果XML是自己制作的,改起来应该不会太难。
无论如何,我建议您使用两种不同的函数 - 一种带有 xPath,一种不带有。
函数 1 (xPath) 仅适用于修改后的 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;
}
函数 2,适用于新旧 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;
}
编辑:
在评论中,您问:“是否可以将主机,dbName等连接节点......分开并保存在特定变量中”?
我不明白他们创建这个语法有什么问题:
$user = getConString( 'jfhsjfhksdjfhsjkfhksjfsdk' );
mysqli_connect ( $user['host'], $user['username'], $user['dbPass'], $user['dbName'] );
顺便说一句,您可以通过这种方式将 returned 值放在单独的变量中:
$user = getConString( 'jfhsjfhksdjfhsjkfhksjfsdk' );
foreach( $user as $key => $val ) $$key = $val;
mysqli_connect ( $host, $username, $dbPass, $dbName );
或者 - 如果您想要特定的变量名称 - 以这种方式更改上面的第二个函数:
(...)
$retval = array();
foreach( $user->connection[0] as $key => $val )
{ $retval[] = trim($val); }
(...)
然后这样调用:
list( $dbHost, $dbUser, $dbDb, $dbPass ) = getConString( 'jfhsjfhksdjfhsjkfhksjfsdk' );
mysqli_connect ( $dbHost, $dbUser, $dbPass, $dbDb );
您可以将 list
中的变量名称更改为您喜欢的名称。函数修改是必要的,因为 list
不适用于关联数组。
- 查看更多关于 Whitespace in XML
- 查看更多关于list() constructor
我的xml结构如下:
<?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>
我编写了遍历所有 xml 节点的代码:
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();
}
}
}
我想要实现的是当 $node 等于:
jfhsjfhksdjfhsjkfhksjfsdk
连接节点以数组形式返回,我该如何实现?
更新:
对于不理解的人,我只是希望如果我插入令牌:jfhsjfhksdjfhsjkfhksjfsdk
将返回用户与令牌 jfhsjfhksdjfhsjkfhksjfsdk
的连接。所以在这种情况下,我想获取 connection
节点的所有内容并创建一个连接字符串:
<connection>
<host>
localhost
</host>
<username>
root
</username>
<dbName>
Test
</dbName>
<dbPass>
123456789
</dbPass>
</connection>
假设您不反对使用 DOMDocument
而不是 simpleXML
那么您应该可以使用以下内容。如果不是,您必须使用 simpleXML
XPath 查询可以移植到 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 );
您可以将这些选项之一变成一个函数,但您应该能够理解如何去做,看看这段代码。这将向您展示如何检索您想要的信息。
选项 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; }
}
选项 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 />";
首先,关于您的 XML 代码的一些注意事项。我不知道你真正的 XML 是否完全按照上面的格式,但如果是,重要的是要强调 XML 空格行为不同于 HTML:通常没有 DTD 或 XML 模式定义,所有空格都是重要的空格,应该保留。同样对于 DTD 或 XML 模式定义,内容中的空格很重要。
这意味着 XML:
<token>
jfhsjfhksdjfhsjkfhksjfsdk
</token>
<token>
假定值 '\n jfhsjfhksdjfhsjkfhksjfsdk\n'
(\n = 换行符)而不是 'jfhsjfhksdjfhsjkfhksjfsdk'
。
这使得在不预先修改 xml 的情况下使用 xPath 很难找到令牌(您可以使用正则表达式)。您可以为此使用 contains()
xPath 语法,但(理论上)它可以 return 多个结果。
我不知道你是否测试过上面的代码,还有 $value->__toString()
return 类似 '\n jfhsjfhksdjfhsjkfhksjfsdk\n'
的东西(它可以根据缩进级别而改变)。要 return 只有令牌值,您必须更改您的代码:
return trim( $value->__toString() );
我的建议是无论如何改变你的XML:
<user>
<name>foo</name>
<token>jfhsjfhksdjfhsjkfhksjfsdk</token>
<connection>
<host>localhost</host>
<username>root</username>
<dbName>Test</dbName>
<dbPass>123456789</dbPass>
</connection>
</user>
因为这是最正确的数据存储方式:如果XML是自己制作的,改起来应该不会太难。
无论如何,我建议您使用两种不同的函数 - 一种带有 xPath,一种不带有。
函数 1 (xPath) 仅适用于修改后的 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;
}
函数 2,适用于新旧 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;
}
编辑:
在评论中,您问:“是否可以将主机,dbName等连接节点......分开并保存在特定变量中”?
我不明白他们创建这个语法有什么问题:
$user = getConString( 'jfhsjfhksdjfhsjkfhksjfsdk' );
mysqli_connect ( $user['host'], $user['username'], $user['dbPass'], $user['dbName'] );
顺便说一句,您可以通过这种方式将 returned 值放在单独的变量中:
$user = getConString( 'jfhsjfhksdjfhsjkfhksjfsdk' );
foreach( $user as $key => $val ) $$key = $val;
mysqli_connect ( $host, $username, $dbPass, $dbName );
或者 - 如果您想要特定的变量名称 - 以这种方式更改上面的第二个函数:
(...)
$retval = array();
foreach( $user->connection[0] as $key => $val )
{ $retval[] = trim($val); }
(...)
然后这样调用:
list( $dbHost, $dbUser, $dbDb, $dbPass ) = getConString( 'jfhsjfhksdjfhsjkfhksjfsdk' );
mysqli_connect ( $dbHost, $dbUser, $dbPass, $dbDb );
您可以将 list
中的变量名称更改为您喜欢的名称。函数修改是必要的,因为 list
不适用于关联数组。
- 查看更多关于 Whitespace in XML
- 查看更多关于list() constructor