获取 PHP 中 XML/XMP 标签的值

Get Value of XML/XMP tag in PHP

我有这个 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]

非常感谢你在这方面的帮助。

谢谢

这是我最终使用的解决方案:

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

不使用正则表达式解析XML。使用 XML 解析器 (DOM) 和 Xpath。 Xpath 是 DOM.

的 select 节点的表达式语言

首先创建一个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 并匹配根节点,即使命名空间 prefix/alias 不同。

现在您可以使用 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) ""
}