PHP & XML: как сравнить текстовое содержимое двух элементов XML? - PullRequest
0 голосов
/ 25 октября 2018

Я пытаюсь написать сценарий, который просматривает три существующих XML-документа и компилирует четвертый XML-документ, содержащий все морфемы (лингвист-говорящий для частей слов) в существующих трех.Я пытаюсь убедиться, что эта новая база данных морфем не содержит дубликатов, и у меня возникают проблемы с тем, чтобы она не добавляла дубликаты.Ниже я опубликую соответствующий фрагмент кода, а весь фрагмент соответствующего кода внизу.

Проверка на наличие дубликатов выглядит следующим образом: ((string)$source == (string)$storySource), где $ source и $ storySource оба являются простыми элементами XMLE, подобными этому: <m>text</m>.Может кто-нибудь сказать мне, где я ошибся?

Лучший, Джимми

Вот весь цикл для прохождения через один из файлов XML.

$storycorpus = new SimpleXMLElement($file,null,true);
$storyEntries = $storycorpus->xpath("//morpheme");
foreach($storyEntries as $entry){
    // check to see if in morpheme database. we will match the Pomo and the English, hence, if either is not a match,
    // we will add a new morpheme
    $storySource = $entry->m;
    $storyGloss = $entry->g;
    // set a variable equal to false
    $foundInDB = false; 

    //we will loop through the database looking for a match.    
    foreach($morphemeEntries as $existingMorpheme){
        $source = $existingMorpheme->source;
        $gloss = $existingMorpheme->gloss;

        // if we find a match, we will set our variable to be true and break out of the morpheme DB loop
        if(((string)$source == (string)$storySource) && ((string)$gloss == (string)$storyGloss)){
            $foundInDB = true; // problem: this line isn't firing
            break;
        }
    }
    // after the morphemeDB loop, we will check to see if the var is true. 
    if($foundInDB == true){
        // if it is true, we don't need to enter anything and can 
        // go to the next entry
        continue;
    } else{
        // if we didn't find a match, create a new morpheme
        $newMorphemeEntry = $morphemeDB->addChild("morpheme");
        $newMorphemeEntry->addChild("source", $storySource);
        $newMorphemeEntry->addChild("gloss", $storyGloss);
        $newMorphemeEntry->addChild("root", $storySource);
        $newMorphemeEntry->addChild("hypernym", $storySource);
        $newMorphemeEntry->addChild("link", "S");
        if(substr($storySource, 0, 1) == "-"){
            $newMorphemeEntry->addChild("affix", "suffix");
        } elseif(substr($storySource, -1, 1) == "-"){
            $newMorphemeEntry->addChild("affix", "prefix");
        } else{
            $newMorphemeEntry->addChild("affix", "root");
        }
    }
}

Хорошо, такЯ переписал блок и использовал DOMDocument вместо SimpleXML, и мне все еще не повезло в предотвращении дублирования.Вот новый код

    // check to see if in morpheme database. we will match the Pomo and the English, hence, if either is not a match,
    // we will add a new morpheme
    $phraseSource = $entry->nodeValue;
    $phraseGlossId = $entry->getAttribute("id");
    $phraseGloss = $xpath2->query("//g[@id =\"$phraseGlossId\"]")->item(0)->nodeValue;
    // set a variable equal to false
    $foundInDB = false; 

    //we will loop through the database looking for a match.    
    foreach($morphemeEntries as $existingMorpheme){
        $source = $existingMorpheme->getElementsByTagName("source")->item(0)->nodeValue;
        $gloss = $existingMorpheme->getElementsByTagName("gloss")->item(0)->nodeValue;
        // if we find a match, we will set our variable to be true and break out of the morpheme DB loop
        if(($source == $phraseSource) && ($gloss == $phraseGloss)){
            $foundInDB = true; // problem: this line isn't firing
            break;
        }
    }
    // after the morphemeDB loop, we will check to see if the var is true. 
    if($foundInDB == true){
        // if it is true, we don't need to enter anything and can 
        // go to the next entry
        continue;
    } else{
        // if we didn't find a match, create a new morpheme
        $newMorphemeEntry = $morphemeXmlDoc->createElement("morpheme");

        $newMorphemeSource = $morphemeXmlDoc->createElement("source");
        $newMorphemeSource->nodeValue = $phraseSource;
        $newMorphemeEntry->appendChild($newMorphemeSource);

        $newMorphemeGloss = $morphemeXmlDoc->createElement("gloss");
        $newMorphemeGloss->nodeValue = $phraseGloss;
        $newMorphemeEntry->appendChild($newMorphemeGloss);

        $newMorphemeRoot = $morphemeXmlDoc->createElement("root");
        $newMorphemeRoot->nodeValue = $phraseSource;
        $newMorphemeEntry->appendChild($newMorphemeRoot);

        $newMorphemeHypernym = $morphemeXmlDoc->createElement("hypernym");
        $newMorphemeHypernym->nodeValue = $phraseSource;
        $newMorphemeEntry->appendChild($newMorphemeHypernym);

        $newMorphemeLink = $morphemeXmlDoc->createElement("link");
        $newMorphemeLink->nodeValue = "P";
        $newMorphemeEntry->appendChild($newMorphemeLink);

        $newMorphemeAffix = $morphemeXmlDoc->createElement("affix");
        $newMorphemeAffix->nodeValue = $phraseGloss;

        if(substr($phraseSource, 0, 1) == "-"){
            $newMorphemeAffix->nodeValue = "suffix";
        } elseif(substr($phraseSource, -1, 1) == "-"){
            $newMorphemeAffix->nodeValue = "prefix";
        } else{
            $newMorphemeAffix->nodeValue = "root";
        }
        $newMorphemeEntry->appendChild($newMorphemeAffix);

        $morphemeRootNode->appendChild($newMorphemeEntry);
    }
}

Вот то, что ищет скрипт для создания нового XML-листа:

<phrasicon>
<phrase id="4">
    <ref1>ES</ref1>
    <source>t̪o: xa jo: k'ala:</source>
    <morpheme>
      <m id="4.1">t̪o:</m>
      <m id="4.2">xa</m>
      <m id="4.3">jo:</m>
      <m id="4.4">k'ala:</m>
    </morpheme>
    <gloss lang="en">
      <g id="4.1">me</g>
      <g id="4.2">water</g>
      <g id="4.3">for</g>
      <g id="4.4">die</g>
    </gloss>
    <translation lang="en">I'm dying for water.</translation>
    <media1 mimeType="audio/wav" url="im_dying_for_water.wav"/>
    <ref2/>
    <media2 mimeType="" url=""/>
    <ref3/>
    <media3 mimeType="" url=""/>
  </phrase>
</phrasicon>

Вот как должен выглядеть новый XML-лист морфемы

<?xml version="1.0" encoding="UTF-8"?>
<morphemedatabase>
<morpheme>
  <source>t̪o:</source>
  <gloss>me</gloss>
  <root>t̪o:</root>
  <hypernym>t̪o:</hypernym>
  <link>P</link>
  <affix>root</affix>
</morpheme>
</morphemedatabase>

Ответы [ 2 ]

0 голосов
/ 25 октября 2018

Я предполагаю, что $morphemeEntries является фиксированным списком SimpleXMLElement объектов и не будет обновляться с добавленными узлами.Я предлагаю использовать $morphemeDB объект для проверки.Кроме того, вы можете заменить цикл на выражение Xpath.

$storySource = $entry->m;
$storyGloss = $entry->g;

$foundInDB = count(
  $morphemeDB->xpath(
    sprintf('.//morpheme[source="%s" and gloss="%s"]', $storySource, $storyGloss)
  )
) > 0; 

В DOM то же самое возможно с DOMXpath::evaluate():

$phraseSource = $xpathSource->evaluate('string(m)', $entry);
$phraseGloss = $xpathSource->evaluate('string(g)', $entry);

$foundInDB = $xpathTarget->evaluate(
  sprintf(
    'count(//morpheme[source="%s" and gloss="%s"]) > 0', 
    $storySource, 
    $storyGloss
  )
);

В реализации DOM вы можете вкладывать createElement()в appendChild(), но вы должны добавить содержимое в виде текстовых узлов (для правильного экранирования):

$newMorphemeEntry = $morphemeRootNode->appendChild(
  $morphemeXmlDoc->createElement("morpheme")
);
$newMorphemeEntry
  ->appendChild($morphemeXmlDoc->createElement("source"))
  ->appendChild($morphemeXmlDoc->createTextNode($phraseSource));
$newMorphemeEntry
  ->appendChild($morphemeXmlDoc->createElement("gloss"))
  ->appendChild($morphemeXmlDoc->createTextNode($phraseGloss));
0 голосов
/ 25 октября 2018

Не пытайтесь привести к (строке) перед сравнением.вместо этого вызовите метод ->asXML() для каждого элемента.замените это:

if(((string)$source == (string)$storySource) && ((string)$gloss == (string)$storyGloss))

на это:

if(($source->asXML() == $storySource->asXML()) && ($gloss->asXML() == $storyGloss->asXML()))

или для сравнения содержащейся строки (исключая теги)

if(($source->__toString() == $storySource->__toString()) && ($gloss->__toString() == $storyGloss->__toString()))

Проблема заключается в том, что SimpleXMLElementне является "классическим" объектом PHP.SimpleXML построен с использованием «живого» API, связанного с внутренним представлением документа XML.

Страница руководства по Сравнение объектов говорит: «Два экземпляра объекта равны, если они имеют одинаковые атрибуты изначения, и являются экземплярами одного и того же класса. "

в print_r () или var_dump () в элементе SimpleXMLElement отображается как свойства, представляющие дочерние узлы и атрибуты.Однако фактическая реализация содержит только указатель на структуру памяти, созданную при анализе XML, которая будет отличаться, даже если вы анализируете одну и ту же строку дважды.Таким образом, простое сравнение двух объектов SimpleXMLElement с == никогда не вернет true.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...