提问人:cheeseus 提问时间:10/27/2023 最后编辑:cheeseus 更新时间:10/27/2023 访问量:26
PHP SimpleXML:按属性值访问节点
PHP SimpleXML: access node by attribute value
问:
我有以下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”的节点是否存在。(有些文件有,有些则没有。如果它存在,我需要更新它。如果它不存在,我需要创建它。prop
type
我使用 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”的节点不存在,即如果未设置变量,则创建它:prop
type
$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_name
foreach
$prop = $new_TM_name
foreach
$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 的新手,我一直在阅读,但我似乎找不到正确的方法。帮忙。
答:
据我所知 - 创建一个新对象就像你所期望的那样,所以主要问题似乎是更新现有节点的值(如果存在)。
此版本使用 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,这是一个全新的学习领域。
评论
$prop
prop
prop
$prop[0]
评论
if
/* if exists, assign its value to the $TM_name variable */
if
$type
$prop