PHP SimpleXML:按属性值访问节点

PHP SimpleXML: access node by attribute value

提问人:cheeseus 提问时间:10/27/2023 最后编辑:cheeseus 更新时间:10/27/2023 访问量:26

问:

我有以下XML(这只是标题):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tmx SYSTEM "tmx14.dtd">
<tmx version="1.4">
<header creationtool="TDC Analysis Package" creationtoolversion="org.gs4tr.tm3.tmx.Version" segtype="sentence" o-tmf="unknown" adminlang="EN-US" srclang="EN" datatype="unknown" creationdate="20221006T184234Z">
    <prop type="x-Recognizers">RecognizeAll</prop>
    <prop type="x-IncludesContextContent">True</prop>
    <prop type="x-TMName">sample_tmx.tmx</prop>
    <prop type="x-TokenizerFlags">DefaultFlags</prop>
    <prop type="x-WordCountFlags">DefaultFlags</prop>
</header>

我需要首先检查属性为“x-TMName”的节点是否存在。(有些文件有,有些则没有。如果它存在,我需要更新它。如果它不存在,我需要创建它。proptype

我使用 SimpleXML 解析这些文件。起初,我使用的是:

if(isset($xmlObj->header->prop[2])) { 
    $TM_name = $xmlObj->header->prop[2];
}

要访问它并更新它:

$xmlObj->header->prop[2] = $new_TM_name;

但是,这并不可靠,因为第三个位置可能有所不同。因此,经过大量的阅读和实验,我设法检查它是否存在并像这样阅读:prop

$fileName = "INVERTED_sample_tmx.tmx";

/* read TMX file contents */
$uploadedFile = "user_files/".$fileName;
$xmlStr = file_get_contents($uploadedFile);
$xmlObj = simplexml_load_string($xmlStr);

/* extract <header> <prop>s */
$props = $xmlObj->header->prop;
/* loop them to check if the type='x-TMName' attribute exists */
foreach($props as $prop) {
    $type = (string)$prop->attributes()->type;
    /* if exists, assign its value to the $TM_name variable */
        if($type == "x-TMName") {
            $TM_name = $prop;
            //$new_TM_name = "INVERTED ".$TM_name;
            //var_dump($prop);
        }
}

如果属性为“x-TMName”的节点不存在,即如果未设置变量,则创建它:proptype$TM_name

if(isset($TM_name)) {
    $new_TM_name = "INVERTED ".$TM_name;
    echo "Old TM name is ".$TM_name." and new TM name is ".$new_TM_name;
}
else {
    /* use the fileName as the TM name */
    $new_TM_name = "INVERTED ".$fileName;
    if($new_prop = $xmlObj->header->addChild('prop', $new_TM_name)) {
        $new_prop->addAttribute('type', "x-TMName2");
        echo "new prop added";
    }
}

这种方法的问题在于我无法用 更新节点,因为我不知道如何访问它。当我尝试在上面的循环中使用 更新它时,页面陷入了无休止的打印循环中。而且我也不知道如何在循环之外访问它。我试过:$new_TM_nameforeach$prop = $new_TM_nameforeach

$headerProps = $xmlObj->header->prop['x-TMName']
or
$headerProps = $xmlObj->header->prop->{'x-TMName'}
or
$headerProps = (string)$xmlObj->header->prop->attributes()->type->{'x-TMName'};
var_dump($headerProps);

这些都打印为空。编辑:虽然我的问题现在已经解决,但我仍然不明白为什么上述方法无法选择我想要的元素,我必须使用循环。我在这里找到了几十个答案,这些答案提供了与我类似的问题的答案。有人可以解释一下他们有什么问题吗?编辑结束。foreach

我是使用 XML 和 SimpleXML 的新手,我一直在阅读,但我似乎找不到正确的方法。帮忙。

php xml simplexml

评论

0赞 CBroe 10/27/2023
在你下面的评论中,你知道它存在 - 那么你为什么不在那里更新它呢?if/* if exists, assign its value to the $TM_name variable */
0赞 cheeseus 10/27/2023
@CBroe,我不知道如何访问它。我尝试过的方法(如下所列)都不起作用。
0赞 CBroe 10/27/2023
在该语句之前,您已经访问了该节点,以通过变量确定 - 的值。也就是说,变量 foreach 将当前项目放入其中。if$type$prop

答:

0赞 Nigel Ren 10/27/2023 #1

据我所知 - 创建一个新对象就像你所期望的那样,所以主要问题似乎是更新现有节点的值(如果存在)。

此版本使用 SimpleXML 的“功能”,它允许您在引用元素本身的同时设置 XML 元素的值。

在循环中,$prop将是一个 SimpleXMLElement 对象,因此要设置此对象的值(而不是$prop为变量),您可以使用 ...$prop[0]

foreach($props as $prop) {
    /* if exists, assign its value to the $TM_name variable */
    if((string)$prop['type'] == "x-TMName") {
        $TM_name = (string)$prop;
        // Update the node value
        $prop[0] = "INVERTED ".$TM_name;
    }
}

您可以使用 XPath 来查找元素,而不仅仅是使用循环。它看起来要简单得多 - 但是您需要开始学习 XPath,这是一个全新的学习领域。

评论

0赞 cheeseus 10/27/2023
它有效!我只尝试过,这让页面陷入了循环。我不认为添加键号(我不确定我是否使用了正确的术语)会有所帮助,因为节点可能处于不同的位置。但是我只是测试了将所述内容移动到不同的地方(最后),并且它得到了整齐的更新。谢谢!你能解释一下为什么它在这里吗?$proppropprop$prop[0]