2015-07-07 12 views
1

У меня есть эта строка XMP $ XML:Получить значение тега XML/XMP в PHP

<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: Прямоугольник и MPReg: PersonDisplayName. Я хочу прочитать значение Rectangle только в том случае, если есть имя PersonDisplay в том же теге.

Я попытался преобразования 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] 

Я очень ценю вашу помощь на этом.

Спасибо

+1

[ 'DOMDocument :: getElementsByTagNameNS'] (HTTP: // PHP.net/manual/en/domdocument.getelementsbytagnamens.php) будет _proper_ способом получить эти _namespaced_ элементы. – CBroe

ответ

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 извлекает все описания РДФ элементов внутри ИММС узла областей элемента. Для каждого описания два выражения выбирают прямоугольник (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

Это решение, которое я закончил с использованием:

//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); 
Смежные вопросы