Загадка XML-анализа - PullRequest
       16

Загадка XML-анализа

1 голос
/ 28 октября 2011

ОБНОВЛЕНИЕ: я переработал вопрос, чтобы показать прогресс, который я сделал, и, возможно, упростить ответ.

ОБНОВЛЕНИЕ 2: я добавил еще одно значение в XML.Расширение доступно в каждом почтовом индексе.Каждый элемент может иметь несколько элементов, разделенных вкладкой.Так что это будет структурировано так.Платформа> Расширение (подгруппа)> Имя> Заголовок.Если элемент имеет более одного расширения, он появится в нескольких местах.

У меня есть следующий XML-файл.

<Item>
    <Platform>Windows</Platform>
    <Ext>gif    jpeg    doc</Ext>
    <Name>File Group 1</Name>
    <Title>This is the first file group</Title>
    <DownloadPath>/this/windows/1/1.zip</DownloadPath>
</Item>
<Item>
    <Platform>Windows</Platform>
    <Ext>gif    doc</Ext>
    <Name>File Group 1</Name>
    <Title>This is the first file group</Title>
    <DownloadPath>/this/windows/1/2.zip</DownloadPath>
</Item>
<Item>
    <Platform>Windows</Platform>
    <Ext>gif</Ext>
    <Name>File Group 1</Name>
    <Title>This is in the same group but has a different title</Title>
    <DownloadPath>/this/windows/1/3.zip</DownloadPath>
</Item>
<Item>
    <Platform>Mac</Platform>
    <Ext>gif    jpeg    doc</Ext>
    <Name>File Group 1</Name>
    <Title>This has the same group name but a different platform. Because it has the same title and name the files are added to this array below.</Title>
    <DownloadPath>/this/mac/1/1.zip</DownloadPath>
</Item>
<Item>
    <Platform>Mac</Platform>
    <Ext>jpeg   doc</Ext>
    <Name>File Group 1</Name>
    <Title>This has the same group name but a different platform. Because it has the same title and name the files are added to this array below.</Title>
    <DownloadPath>/this/mac/1/2.zip</DownloadPath>
</Item>
<Item>
    <Platform>Windows</Platform>
    <Ext>gif    jpeg    doc</Ext>
    <Name>File Group 2</Name>
    <Title>This is the second file group</Title>
    <DownloadPath>/this/windows/2/1.zip</DownloadPath>
</Item>
<Item>
    <Platform>Windows</Platform>
    <Ext>gif    jpeg    doc</Ext>
    <Name>File Group 2</Name>
    <Title>This is the second file group</Title>
    <DownloadPath>/this/windows/2/2.zip</DownloadPath>
</Item>
<Item>
    <Platform>Mac</Platform>
    <Ext>gif    jpeg    doc</Ext>
    <Name>File Group 3</Name>
    <Title>This is the second mac file group really.</Title>
    <DownloadPath>/this/windows/3/1.zip</DownloadPath>
</Item>

Я хочу иметь возможность просмотреть его и отсортироватьпоэтому я могу вставить его в схему нормализованной таблицы.Вот формат, который я хотел бы создать для массива.

[Windows] => Array (
    [0] => array(
        "Name" => "File Group 1",
        "Title" => "This is the first file group",
        "Files" => array(
            [0] => array(
                "DownloadPath" => "/this/windows/1/1.zip"
            ),
            [1] => array(
                "DownloadPath" => "/this/windows/1/2.zip"
            )
        )
    ),
    [1] => array(
        "Name" => "File Group 1",
        "Title" => "This has the same name but has a different title, so it should be seperate.",
        "Files" => array(
            [0] => array(
                "DownloadPath" => "/this/windows/1/3.zip"
            )
        )
    ),
    [1] => array(
        "Name" => "File Group 2",
        "Title" => "This is the second file group",
        "Files" => array(
            [0] => array(
                "DownloadPath" => "/this/windows/2/1.zip"
            ),
            [1] => array(
                "DownloadPath" => "/this/windows/2/2.zip"
            )
        )
    )
),
[Mac] => Array(
    [0] => array(
        "Name" => "File Group 1",
        "Title" => "This has the same group name but a different platform. Because it has the same title and name the files are added to this array below.",
        "Files" => array(
            [0] => array(
                "DownloadPath" => "/this/mac/1/1.zip"
            ),
            [1] => array(
                "DownloadPath" => "/this/mac/1/2.zip"
            )
        )
    ),
    [1] => array(
        "Name" => "File Group 3",
        "Title" => "This is the second mac file group really.",
        "Files" => array(
            [0] => array(
                "DownloadPath" => "/this/mac/1/1.zip"
            ),
            [1] => array(
                "DownloadPath" => "/this/mac/1/2.zip"
            )
        )
    ),
)

Вот то, что я получил до сих пор с моим php

<code>    $scrape_xml = "files.xml";
    $xml = simplexml_load_file($scrape_xml);

$groups = array();

foreach ($xml->Item as $file){

            if (!isset($groups[stripslashes($file->Platform)][stripslashes($file->Name)][stripslashes($file->Title)])){

                $groups[stripslashes($file->Platform)][stripslashes($file->Name)][stripslashes($file->Title)] = array(
                    'Platform' => $file->Platform,
                    'Name' => $file->Name,
                    'Title' => $file->Title
                );

            }

   $groups[stripslashes($file->Platform)][stripslashes($file->Name)][stripslashes($file->Title)]['Files'][] = $file->DownloadPath;

}

echo "count=" . $i;

echo "<pre>";
print_r($groups);
echo "
";

это дает мне этот результат

Array
(
    [Windows] => Array
        (
            [File Group 1] => Array
                (
                    [This is the first file group] => Array
                        (
                            [Platform] => SimpleXMLElement Object
                                (
                                    [0] => Windows
                                )

                            [Name] => SimpleXMLElement Object
                                (
                                    [0] => File Group 1
                                )

                            [Title] => SimpleXMLElement Object
                                (
                                    [0] => This is the first file group
                                )

                            [Files] => Array
                                (
                                    [0] => SimpleXMLElement Object
                                        (
                                            [0] => /this/windows/1/1.zip
                                        )

                                    [1] => SimpleXMLElement Object
                                        (
                                            [0] => /this/windows/1/2.zip
                                        )

                                )

                        )

                    [This is in the same group but has a different title] => Array
                        (
                            [Platform] => SimpleXMLElement Object
                                (
                                    [0] => Windows
                                )

                            [Name] => SimpleXMLElement Object
                                (
                                    [0] => File Group 1
                                )

                            [Title] => SimpleXMLElement Object
                                (
                                    [0] => This is in the same group but has a different title
                                )

                            [Files] => Array
                                (
                                    [0] => SimpleXMLElement Object
                                        (
                                            [0] => /this/windows/1/3.zip
                                        )

                                )

                        )

                )

            [File Group 2] => Array
                (
                    [This is the second file group] => Array
                        (
                            [Platform] => SimpleXMLElement Object
                                (
                                    [0] => Windows
                                )

                            [Name] => SimpleXMLElement Object
                                (
                                    [0] => File Group 2
                                )

                            [Title] => SimpleXMLElement Object
                                (
                                    [0] => This is the second file group
                                )

                            [Files] => Array
                                (
                                    [0] => SimpleXMLElement Object
                                        (
                                            [0] => /this/windows/2/1.zip
                                        )

                                    [1] => SimpleXMLElement Object
                                        (
                                            [0] => /this/windows/2/2.zip
                                        )

                                )

                        )

                )

        )

    [Mac] => Array
        (
            [File Group 1] => Array
                (
                    [This has the same group name but a different platform. Because it has the same title and name the files are added to this array below.] => Array
                        (
                            [Platform] => SimpleXMLElement Object
                                (
                                    [0] => Mac
                                )

                            [Name] => SimpleXMLElement Object
                                (
                                    [0] => File Group 1
                                )

                            [Title] => SimpleXMLElement Object
                                (
                                    [0] => This has the same group name but a different platform. Because it has the same title and name the files are added to this array below.
                                )

                            [Files] => Array
                                (
                                    [0] => SimpleXMLElement Object
                                        (
                                            [0] => /this/mac/1/1.zip
                                        )

                                    [1] => SimpleXMLElement Object
                                        (
                                            [0] => /this/mac/1/2.zip
                                        )

                                )

                        )

                )

            [File Group 3] => Array
                (
                    [This is the second mac file group really.] => Array
                        (
                            [Platform] => SimpleXMLElement Object
                                (
                                    [0] => Mac
                                )

                            [Name] => SimpleXMLElement Object
                                (
                                    [0] => File Group 3
                                )

                            [Title] => SimpleXMLElement Object
                                (
                                    [0] => This is the second mac file group really.
                                )

                            [Files] => Array
                                (
                                    [0] => SimpleXMLElement Object
                                        (
                                            [0] => /this/windows/3/1.zip
                                        )

                                )

                        )

                )

        )

)

ОБНОВЛЕНИЕ 2: Новая структура массива

[Windows] => Array (
    [gif] =>Array(
        [0] => array(
            "Name" => "File Group 1",
            "Title" => "This is the first file group",
            "Files" => array(
                [0] => array(
                    "DownloadPath" => "/this/windows/1/1.zip"
                ),
                [1] => array(
                    "DownloadPath" => "/this/windows/1/2.zip"
                )
            )
        )
    ),
    [jpeg] => array(
        [0] => array(
            "Name" => "File Group 1",
            "Title" => "This is the first file group",
            "Files" => array(
                [0] => array(
                    "DownloadPath" => "/this/windows/1/1.zip"
                ),
                [1] => array(
                    "DownloadPath" => "/this/windows/1/2.zip"
                )
            )
        ),
        [1] => array(
            "Name" => "File Group 2",
            "Title" => "This is the second file group",
            "Files" => array(
                [0] => array(
                    "DownloadPath" => "/this/windows/2/1.zip"
                ),
                [1] => array(
                    "DownloadPath" => "/this/windows/2/2.zip"
                )
            )
        )
    ),
    [doc] => array(
        [0] => array(
            "Name" => "File Group 1",
            "Title" => "This is the first file group",
            "Files" => array(
                [0] => array(
                    "DownloadPath" => "/this/windows/1/1.zip"
                ),
                [1] => array(
                    "DownloadPath" => "/this/windows/1/2.zip"
                )
            )
        ),
        [1] => array(
            "Name" => "File Group 1",
            "Title" => "This has the same name but has a different title, so it should be seperate.",
            "Files" => array(
                [0] => array(
                    "DownloadPath" => "/this/windows/1/3.zip"
                )
            )
        ),
        [2] => array(
            "Name" => "File Group 2",
            "Title" => "This is the second file group",
            "Files" => array(
                [0] => array(
                    "DownloadPath" => "/this/windows/2/1.zip"
                ),
                [1] => array(
                    "DownloadPath" => "/this/windows/2/2.zip"
                )
            )
        )
    )
),
[Mac] => Array(
    [gif] => array(
        [0] => array(
            "Name" => "File Group 2",
            "Title" => "This is the second file group",
            "Files" => array(
                [0] => array(
                    "DownloadPath" => "/this/mac/2/1.zip"
                ),
                [1] => array(
                    "DownloadPath" => "/this/mac/2/2.zip"
                )
            )
        ),
        [1] => array(
            "Name" => "File Group 2",
            "Title" => "This is the second file group",
            "Files" => array(
                [0] => array(
                    "DownloadPath" => "/this/mac/2/1.zip"
                ),
                [1] => array(
                    "DownloadPath" => "/this/mac/2/2.zip"
                )
            )
        ),

    )
    [jepg] => array(
        [0] => array(
            "Name" => "File Group 2",
            "Title" => "This is the second file group",
            "Files" => array(
                [0] => array(
                    "DownloadPath" => "/this/mac/2/1.zip"
                ),
                [1] => array(
                    "DownloadPath" => "/this/mac/2/2.zip"
                )
            )
        )
    )
    [doc] => array(
        [0] => array(
            "Name" => "File Group 1",
            "Title" => "This has the same group name but a different platform. Because it has the same title and name the files are added to this array below.",
            "Files" => array(
                [0] => array(
                    "DownloadPath" => "/this/mac/1/1.zip"
                ),
                [1] => array(
                    "DownloadPath" => "/this/mac/1/2.zip"
                )
            )
        ),
        [1] => array(
            "Name" => "File Group 3",
            "Title" => "This is the second mac file group really.",
            "Files" => array(
                [0] => array(
                    "DownloadPath" => "/this/mac/1/1.zip"
                ),
                [1] => array(
                    "DownloadPath" => "/this/mac/1/2.zip"
                )
            )
        )
    )
)

ОБНОВЛЕНИЕ 3: В список файлов поступает мусор.

<Item>
        <Platform>Windows</Platform>
        <Ext>gif    jpeg    doc</Ext>
        <Name>File Group 1</Name>
        <Title>This is the first file group</Title>
        <DownloadPath>/this/windows/1/1.zip</DownloadPath>
    </Item>
    <Item>
        <Platform>Windows</Platform>
        <Ext>gif    jpeg    doc</Ext>
        <Name>File Group 1</Name>
        <Title>This is the first file group</Title>
        <DownloadPath>/this/windows/1/2.zip</DownloadPath>
    </Item>
<Item>
        <Platform>Windows</Platform>
        <Ext>gif    jpeg    doc</Ext>
        <Name>File Group 1</Name>
        <Title>This is the first file group</Title>
        <DownloadPath>/this/windows/2/1.zip</DownloadPath>
    </Item>
    <Item>
        <Platform>Windows</Platform>
        <Ext>gif    jpeg    doc</Ext>
        <Name>File Group 1</Name>
        <Title>This is the first file group</Title>
        <DownloadPath>/this/windows/2/2.zip</DownloadPath>
    </Item>

Существует элемент с той же платформой, расширениями, именем и названием. Элементы 3 и 4 выше необходимо пропустить и сохранить их в массив, который я буду обрабатывать позже.

Ответы [ 7 ]

1 голос
/ 31 октября 2011

Вы просто отображаете входные значения в выходной массив, упорядочивая их по-разному, это ваша структура:

Array(
  [... Item/Platform] => Array (
    [... Item/Title as 0-n] => array(
        "Name" => Item/Name,
        "Title" => Item/Title,
        "Files" => array(
            [...] => array(
                "DownloadPath" => Item/DownloadPath
            ),
        )
    ),

Отображение может быть выполнено путем итерации по элементам в XML и сохранения значений в соответствующем месте в новом массиве (я назвал его $build):

$build = array();
foreach($items as $item)
{
    $platform = (string) $item->Platform;
    $title = (string) $item->Title;
    isset($build[$platform][$title]) ?: $build[$platform][$title] = array(
        'Name' => (string) $item->Name,
        'Title' => $title
    );
    $build[$platform][$title]['Files'][] = array('DownloadPath' => (string) $item->DownloadPath);
}
$build = array_map('array_values', $build);

В конце выполняется вызов array_map для преобразования ключей Item/Title в числовые.

И это все, вот демо 1013 *.

Дайте мне знать, если это полезно.

Редактировать: Для ваших обновленных данных это незначительное изменение вышеприведенного, ключевые принципы предыдущего примера все еще существуют, он дополнительно позаботился о дополнительном дублировании для каждого дополнительного расширения на элемент добавив еще одну итерацию внутрь:

$build = array();
foreach($items as $item)
{
    $platform = (string) $item->Platform;
    $title = (string) $item->Title;
    foreach(preg_split("~\s+~", $item->Ext) as $ext)
    {
        isset($build[$platform][$ext][$title])
            ?:$build[$platform][$ext][$title] = array(
                'Name' => (string) $item->Name,
                'Title' => $title
            );
        $build[$platform][$ext][$title]['Files'][]
            = array('DownloadPath' => (string) $item->DownloadPath);
    }
}
$build = array_map(function($v) {return array_map('array_values', $v);}, $build);
0 голосов
/ 31 октября 2011

Это код, который даст вам нужный вам результат. ОБНОВЛЕНИЕ: Это касается последней группы, которую вы просили.

<code>$scrape_xml = "files.xml";
$xml = simplexml_load_file($scrape_xml);
$groups = array();

foreach ($xml->Item as $file){
    $platform = stripslashes($file->Platform);
    $name = stripslashes($file->Name);
    $title = stripslashes($file->Title);
    $extensions = explode('    ', $file->Ext);

    foreach($extensions as $extension)
    {
        if (!isset($groups2[$platform])) $groups2[$platform] = array();
        if (!isset($groups2[$platform][$extension])) $groups2[$platform][$extension] = array();

        $groupFound = false;
        for($idx = 0; $idx < count($groups2[$platform][$extension]); $idx ++) {
            if ($groups2[$platform][$extension][$idx]["Name"] == $name 
                && $groups2[$platform][$extension][$idx]["Title"] == $title) {

                $groups2[$platform][$extension][$idx]["Files"][] =
                    array('DownloadPath' => $file->DownloadPath."");

                $groupFound = true;

                break;
            }
        }

        if ($groupFound) continue;

        $groups2[$platform][$extension][] = 
            array(
                "Name" => $name,
                "Title" => $title,
                "Files" => array(array('DownloadPath' => $file->DownloadPath."")));
    }
}

echo "<br />";
echo "<pre>";
print_r($groups2);
echo "
";
0 голосов
/ 31 октября 2011

Вы можете попробовать это:

<code>$scrape_xml = "files.xml";
$xml = simplexml_load_file($scrape_xml);

$group = array();

foreach ($xml->Item as $file)
{
    $platform = stripslashes($file->Platform);
    $name = stripslashes($file->Name);
    $title = stripslashes($file->Title);
    $downloadPath = stripslashes($file->DownloadPath);

    if(!isset($group[$platform]))
    {
        $group[$platform] = array();
        $group[$platform][] = array("Name" => $name,"Title" => $title, "Files" => array($downloadPath));
    }
    else
    {
        $found = false;

        for($i=0;$i<count($group[$platform]);$i++)
        {
            if($group[$platform][$i]["Name"] == $name  && $group[$platform][$i]["Title"] == $title)
            {
                $group[$platform][$i]["Files"][] = $downloadPath;
                $found = true;
                break;
            }
        }

        if(!$found)
        {
            $group[$platform][] = array("Name" => $name,"Title" => $title, "Files" => array($downloadPath));
        }
    }
}

echo "<pre>".print_r($group,true)."
";
0 голосов
/ 31 октября 2011

Как как то так? Код немного неаккуратный, и для улучшения проверки, вероятно, следует внести изменения.

class XMLFileImporter {
  public $file; //Absolute path to import file
  public $import = array();
  public $xml;
  public $error = false;

  public function __construct($file) {
    $this->file = $file;
    $this->load();
  }

  public function load() {
    if(!is_readable($this->file)) {
      $this->error("File is not readable");
      return false;
    }

    $xml = simplexml_load_file($this->file);
    if(!$xml) {
      $this->error("XML could not be parsed");
      return false;
    }
    $this->xml = json_decode(json_encode($xml));

    return true;
  }

  public function import() {
    $count = $this->parseItems();
    echo "Imported $count rows";

  }

  public function parseItems() {
    if($this->error()){
      return false;
    }

    if(!self::validateXML($this->xml)) {
      $this->error("Invalid SimpleXML object");
      return false;
    }

    if(!self::validateArray($this->xml->Item)) {
      $this->error("Invalid Array 'Item' on SimpleXML object");
      return false;
    }
    $count = 0;
    foreach($this->xml->Item as $item) {
      if($this->parseItem($item)){
        $count++;
      }
    }
    return $count;

  }
  public function parseItem($item) {
    if($this->error()){
      return false;
    }

    if(!self::validateItem($item)) {
      $this->error("Invalid file item");
      return false;
    }

    $item = self::normalizeItem($item);

    $this->handlePlatform((string)$item->Platform);
    $this->handleGroup($item);
    $this->handleSubGroup($item);
    $this->handleFile($item);
    return true;
  }

  public function handlePlatform($platform) {
    if(!isset($this->import[$platform])) {
      $this->import[$platform] = array();
    }

    return true;
  }

  public function handleGroup($item) {
    if(!isset($this->import[$item->Platform][$item->Name])) {
      $this->import[$item->Platform][$item->Name] = array();
    }
    return true;
  }

  public function handleSubGroup($item) {
    if(!isset($this->import[$item->Platform][$item->Name][$item->Title])) {
      $this->import[$item->Platform][$item->Name][$item->Title] = array();
    }
    return true;
  }

  public function handleFile($item) {
    array_push($this->import[$item->Platform][$item->Name][$item->Title],$item->DownloadPath);
  }

  public function error($set=false) {
    if($set){
      $this->error = $set;
      return true;
    }
    return $this->error;
  }

  public static function validateXML($xml) {
    return is_object($xml);
  }
  public static function validateArray($arr,$min=1){
    return (isset($arr) && !empty($arr) && count($arr) > $min);

  }

  public static function validateItem($item){
    return (isset($item->Title)
           && isset($item->Name)
           && isset($item->DownloadPath)
           && isset($item->Platform));

  }

  public static function normalizeItem($item){
    $item->Name = stripslashes(trim((string)$item->Name));
    $item->Title = stripslashes(trim((string)$item->Title));
    $item->Platform = (string)$item->Platform;
    $item->DownloadPath = (string)$item->DownloadPath;

    return $item;
  }

  public function output() {
    print_r($this->import);
    return true;
  }

}

$importer = new XMLFileImporter(dirname(__FILE__)."/files.xml");
$importer->load();
$importer->import();
$importer->output();
var_dump($importer->error());
0 голосов
/ 31 октября 2011

Я предпочитаю DOM DOcument и XPath для себя, так что это то, что я буду делать ...

$xml = '\path\to\your\file.xml';
$doc = new DOMDocument( '1.0', 'UTF-8' );
$doc->load( $xml );

$dxpath = new DOMXPath( $doc );
$items = $dxpath->query( '//Item' );

$db = new PDO( 'mysql:dbname=YOURDB:host=YOURHOST', $DBUSER, $DBPASS );
$ins = $db->prepare('
                    INSERT INTO ur_table
                    ( `platform` , `name` , `title` , `path` )
                    VALUES
                    ( :platform , :name , :title , :path );
                    ');

foreach( $items as $item )
{
    $ins->bindValue( ':platform'     , $item->getElementsByTagName( 'PlatForm' )->item(0)->nodeValue , PDO::PARAM_STR );
    $ins->bindValue( ':name'         , $item->getElementsByTagName( 'Name' )->item(0)->nodeValue     , PDO::PARAM_STR );
    $ins->bindValue( ':title'        , $item->getElementsByTagName( 'Title' )->item(0)->nodeValue    , PDO::PARAM_STR );
    $ins->bindValue( ':DownloadPath' , $item->getElementsByTagName( 'PlatForm' )->item(0)->nodeValue , PDO::PARAM_STR );
    $ins->execute();
}

Нет необходимости в полосках, а что нет - он справится со всеми вами.

0 голосов
/ 31 октября 2011

Вы точно не объяснили, что вы видите неправильно, поэтому мне придется угадать.

Во-первых, в вашем источнике ваш последний DownloadPath равен /this/windows/3/1.zip, хотя предполагается, чтобыть файлом Mac - ошибочно, я уверен, но вывод будет «выглядеть неправильно» с этим.

Далее, если вам нужны строки, а не объекты SimpleXMLElement, вам это нужно (также сделанонекоторые приводят в порядок, чтобы избежать стольких stripslashes() вызовов):

foreach ($xml->Item as $file) {
    $platform = stripslashes((string) $file->Platform);
    $name = stripslashes((string) $file->Name);
    $title = stripslashes((string) $file->Title);
    if( !isset($groups[$platform][$name][$title])) {
        $groups[$platform][$name][$title] = array(
            'Platform' => $platform,
            'Name' => $name,
            'Title' => $title 
        );
    } 
    $groups[$platform][$name][$title]['Files'][] = (string) $file->DownloadPath;
}

Обратите внимание на (string) биты?Они приводят объект к строке, которая позволяет получить доступ к буквальному значению, а не к объекту.Это также причина, по которой ваши ключи массива работали, потому что они были внутренне преобразованы в строки (в качестве ключей массива могут использоваться только строки и целые числа).

Я думаю, что это все, что я могу найти, что может ответить на ваш вопрос.Если это не так, пожалуйста, дайте мне понять, что не так, и я буду рад помочь.

0 голосов
/ 31 октября 2011

начать с объявления

$groups[stripslashes($file->Platform)][stripslashes($file->Name)]
  [stripslashes($file->Title)] = (object)array(
    'Name' => $file->Name,
    'Title' => $file->Title,
    'Files' = (object)array()
  );

Это приблизит вас.

Вы также должны проверить тип каждого XMLElement, чтобы увидеть, является ли он массивом или простым объектом. Тогда относись соответственно.

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