我有这个XMP字符串$ xml:
<x:xmpmeta xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="uuid:faf5bdd5-ba3d-11da-ad31-d33d75182f1b" xmlns:xmp="http://ns.adobe.com/xap/1.0/">
<xmp:CreatorTool>Microsoft Photo Gallery 16.4.3528.331</xmp:CreatorTool>
<xmp:Rating>2</xmp:Rating>
</rdf:Description>
<rdf:Description rdf:about="uuid:faf5bdd5-ba3d-11da-ad31-d33d75182f1b" xmlns:MP="http://ns.microsoft.com/photo/1.2/">
<MP:RegionInfo>
<rdf:Description xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<MPRI:Regions xmlns:MPRI="http://ns.microsoft.com/photo/1.2/t/RegionInfo#">
<rdf:Bag xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:li>
<rdf:Description xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<MPReg:Rectangle xmlns:MPReg="http://ns.microsoft.com/photo/1.2/t/Region#">0.144259, 0.358824, 0.065751, 0.098529</MPReg:Rectangle>
</rdf:Description>
</rdf:li>
<rdf:li>
<rdf:Description xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<MPReg:Rectangle xmlns:MPReg="http://ns.microsoft.com/photo/1.2/t/Region#">0.211973, 0.294118, 0.023553, 0.035294</MPReg:Rectangle>
</rdf:Description>
</rdf:li>
<rdf:li>
<rdf:Description xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<MPReg:Rectangle xmlns:MPReg="http://ns.microsoft.com/photo/1.2/t/Region#">0.350343, 0.423529, 0.056919, 0.085294</MPReg:Rectangle>
<MPReg:PersonDisplayName xmlns:MPReg="http://ns.microsoft.com/photo/1.2/t/Region#">xc</MPReg:PersonDisplayName>
</rdf:Description>
</rdf:li>
<rdf:li>
<rdf:Description xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<MPReg:Rectangle xmlns:MPReg="http://ns.microsoft.com/photo/1.2/t/Region#">0.352306, 0.300000, 0.023553, 0.035294</MPReg:Rectangle>
</rdf:Description>
</rdf:li>
<rdf:li>
<rdf:Description xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<MPReg:Rectangle xmlns:MPReg="http://ns.microsoft.com/photo/1.2/t/Region#">0.395486, 0.304412, 0.047105, 0.070588</MPReg:Rectangle>
</rdf:Description>
</rdf:li>
<rdf:li>
<rdf:Description xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<MPReg:Rectangle xmlns:MPReg="http://ns.microsoft.com/photo/1.2/t/Region#">0.823356, 0.560294, 0.095191, 0.142647</MPReg:Rectangle>
</rdf:Description>
</rdf:li>
</rdf:Bag>
</MPRI:Regions>
</rdf:Description>
</MP:RegionInfo>
</rdf:Description>
<rdf:Description xmlns:MicrosoftPhoto="http://ns.microsoft.com/photo/1.0/">
<MicrosoftPhoto:Rating>25</MicrosoftPhoto:Rating>
</rdf:Description>
<rdf:Description xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:title>
<rdf:Alt xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:li xml:lang="x-default">edgf</rdf:li>
</rdf:Alt>
</dc:title>
</rdf:Description>
<rdf:Description xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:description>
<rdf:Alt xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:li xml:lang="x-default">edgf</rdf:li>
</rdf:Alt>
</dc:description>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
我对2个标签感兴趣:MPReg:Rectangle和MPReg:PersonDisplayName。 我想只在同一个标签中有PersonDisplayname才能读取Rectangle值。
我尝试使用以下代码将XMP转换为数组:
function get_xmp_array( &$xmp_raw ) {
$xmp_arr = array();
foreach ( array(
'RectangleCoords' => '<MPReg:Rectangle[^>]+?xmlns:MPReg="([^"]*)"',
'attempt2' => '<MPReg:Rectangle>\s*(.*?)\s*<\/MPReg:Rectangle>'
) as $key => $regex ) {
// get a single text string
$xmp_arr[$key] = preg_match( "/$regex/is", $xmp_raw, $match ) ? $match[1] : '';
// if string contains a list, then re-assign the variable as an array with the list elements
$xmp_arr[$key] = preg_match_all( "/<rdf:li[^>]*>([^>]*)<\/rdf:li>/is", $xmp_arr[$key], $match ) ? $match[1] : $xmp_arr[$key];
// hierarchical keywords need to be split into a third dimension
if ( ! empty( $xmp_arr[$key] ) && $key == 'Hierarchical Keywords' ) {
foreach ( $xmp_arr[$key] as $li => $val ) $xmp_arr[$key][$li] = explode( '|', $val );
unset ( $li, $val );
}
}
return $xmp_arr;
}
但它没有用,它返回了这个:
'RectangleCoords' => string 'http://ns.microsoft.com/photo/1.2/t/Region#'
'attempt2' => string ''
我尝试了多种功能,如:
function getTextBetweenTags($string, $tagname) {
$pattern = "/<$tagname ?.*>(.*)<\/$tagname>/";
preg_match($pattern, $string, $matches);
return $matches[1];
}
此功能仅返回第一场比赛,我不知道如何获得所有比赛。
我也试过这个:
$doc = new DOMDocument();
$doc->loadXML($xml);
$result = $doc->getElementsByTagName('MPReg:Rectangle');
var_dump( $result );
但它什么都没有回复:
object(DOMNodeList)[3]
我真的很感谢你对此的帮助。
谢谢
答案 0 :(得分:2)
不要使用正则表达式来解析XML。使用XML解析器(DOM)和Xpath。 Xpath是一种用于选择DOM节点的表达式语言。
首先创建一个DOM文档,加载XML并为文档创建一个Xpath实例。
$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);
XML使用名称空间,因此现在必须为它们注册前缀别名。 XML中的别名仅对文档有效。在解析时,DOM解析名称空间。您可以将根节点读为{adobe:ns:meta/}:xmpmeta
。
$xpath->registerNamespace('x', 'adobe:ns:meta/');
$xpath->registerNamespace('xmp', 'http://ns.adobe.com/xap/1.0/');
$xpath->registerNamespace('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
$xpath->registerNamespace('MP', 'http://ns.microsoft.com/photo/1.2/');
$xpath->registerNamespace('MPRI', 'http://ns.microsoft.com/photo/1.2/t/RegionInfo#');
$xpath->registerNamespace('MPReg', 'http://ns.microsoft.com/photo/1.2/t/Region#');
这允许Xpath实例解析名称空间。表达式/x:xmpmeta
可以解析为/{adobe:ns:meta/}:xmpmeta
并匹配根节点,即使名称空间前缀/别名不同。
现在您可以使用DOMXpath::evaluate()
来获取节点和值:
foreach ($xpath->evaluate('//MPRI:Regions//rdf:Description') as $description) {
var_dump(
[
'rectangle' => $xpath->evaluate('string(MPReg:Rectangle)', $description),
'person' => $xpath->evaluate('string(MPReg:PersonDisplayName)', $description),
]
);
}
表达式//MPRI:Regions//rdf:Description
获取mpri区域元素节点内的所有rdf描述元素。对于每个描述,两个表达式将矩形(string(MPReg:Rectangle)
)和人物显示名称(string(MPReg:PersonDisplayName)
)取为字符串。
输出:
array(2) {
["rectangle"]=>
string(38) "0.144259, 0.358824, 0.065751, 0.098529"
["person"]=>
string(0) ""
}
array(2) {
["rectangle"]=>
string(38) "0.211973, 0.294118, 0.023553, 0.035294"
["person"]=>
string(0) ""
}
array(2) {
["rectangle"]=>
string(38) "0.350343, 0.423529, 0.056919, 0.085294"
["person"]=>
string(2) "xc"
}
array(2) {
["rectangle"]=>
string(38) "0.352306, 0.300000, 0.023553, 0.035294"
["person"]=>
string(0) ""
}
array(2) {
["rectangle"]=>
string(38) "0.395486, 0.304412, 0.047105, 0.070588"
["person"]=>
string(0) ""
}
array(2) {
["rectangle"]=>
string(38) "0.823356, 0.560294, 0.095191, 0.142647"
["person"]=>
string(0) ""
}
答案 1 :(得分:-1)
这是我最终使用的解决方案:
//This function will return the value of a certain tag
function getTextBetweenTags($string, $tagname, $offset) {
$pattern = "/<$tagname ?.*>(.*)<\/$tagname>/";
preg_match($pattern, $string, $matches, PREG_OFFSET_CAPTURE, $offset);
return $matches;
}
//Initiate variables
$People = array(array("Rectangle" => null, "PersonName" => null)); //will store the people tag informations
$coords = array(); //will store all of the offset values
$ofs = 0; //it willl temporarily store the offset value
$i = 0; //number of results counter
$name=""; // it willl temporarily store the person's name
//It will search the XMP String for the first Rectangle result,
//Then, it will search again, but this time it will search right after the first result
//Hence the use of the offset variable, it will repeat til there is no more rectangle results
do
{
$result = getTextBetweenTags($xml, "MPReg:Rectangle", $ofs);
if( $result ) $ofs = $result[1][1]; else break;
$coords[$i] = $ofs;
$People[$i]["Rectangle"] = $result[1][0];
$i++;
}
while ( $result );
//If there is a Person name it will follow the Rectangle tag
//By that logic, and using the previous variable,
//A reverse search for the Person name will be performed
for ( $j = $i-1 ; $j >= 0 ; $j--)
{
$result = getTextBetweenTags($xml, "MPReg:PersonDisplayName", $coords[$j]);
if( $result )
if ($name != $result[1][0])//If the name is not the same as the previous one
{
$name = $result[1][0];
$People[$j]["PersonName"] = $result[1][0];
}
}
var_dump( $People );