Home 1C 1с внешние приложения 1С СКД - взглянем по новому
1С СКД - взглянем по новому PDF Печать E-mail
Автор: А.Волос   

 

Рекомендовано отчеты в 1С делать с использованием СКД (схема компоновки данных). После создания схемы, ее можно сохранить, для чего существует кнопка в левом нижнем углу формы. При этом образуется файл в формате XML. Как мы знаем этот формат считается универсальным для отображения и хранения данных. Но самое главное и интересное в том, что этот файл можно редактировать непосредственно в тестовом редакторе. В некоторых случаях это намного быстрее, чем интерактивно вводить данные на форме.

Для того, чтобы что-то отредактировать в этом файле, необходимо понять его строение. Проще сказать просмотреть xml-файл конкретного отчета (а это может быть 50000 строк и более). Чтобы не скроллить такое длинное полотно кода, для просмотра xml-файла как нельзя лучше подходит показанная ниже программа. Она написана специально для этой цели.

Эта программа отображает xml-файл в html-книгу следующим образом. В отдельную главу выводит варианты отчета (settingsVariant). В отдельную главу выводит стандартные закладки calculatedField (вычисляемые поля), totalField (ресурсы), parameter (параметры) и тд, а так же Таблицу (field) и Запрос(query) - для каждого из наборов данных. В случае отсутствия наборов данных, но присутствия внешних схем (nestedSchema) каждая внешняя схема так же выводится в отдельную главу.

Это очень удобно. К функционалу программы можно добавить расцветку кода, перед тем как записывать код на страницу книги. Примеры расцветки кода были достаточно подробно рассмотрены в предыдущих статьях

Программа имеет две ветви. В 1-й ветви сканирует схему, не имеющую собственных наборов данных, но имеющую вложенные внешние схемы (отчет АнализСебестоимостиТоваров). Во 2-й ветви - которая разделяется в свою очередь на 2 ветви - схемы имеющий один набор данных (отчет АнализДоступностиТоваров), и схемы имеющие несколько наборов данных (отчет АнализДоходовРасходов).

Основную работу по парсингу выполняет объект класса simpleXML, который создается и инициируется при помощи функции simplexml_load_file(). Далее нам достаточно было применить несколько специфичных функций объекта этого класса.

Парсимый xml-файл надо поместить в папку 'xmlsource'. Результат - html-книга находится в папке 'to1'. В папке 'шаблон' находится чистая html-книга.

Работа программиста похожа на работу ювелира. Он так же ювелирно обрабатывает, шлифует свою программу, как и ювелир золотую штучку. И программа обязательно должна быть красивой. Должна приносить эстетическое удовольствие своим кодом, где не должно быть ни одной лишней строчки. Не терпит неряшливости. Если программа не красива, то скорее всего это плохо работающая программа. Это так, к слову.

Скачать программу: xml2html.zip

<?php
/** Program from Albert Volos April 2016 
* (C) "1С Отображение СКД в html-книгу" 
* Автор: Альберт Волос 
* http://www.pick4you.ru 
* 
**/  
require_once(dirname(__FILE__) . '/' . 'utilities/util_func.php');

// Получаем полный список файлов и каталогов внутри каталога xmlsource 
$folder = "xmlsource";
$files = scandir($folder);

$count_f = count($files);
if($count_f < 3){echo("Каталог пуст\n"); exit;}

$file = '';
        
foreach($files as $file) {//находим один xml-файл, - это одна итерация цикла!
    // Отбрасываем текущий и родительский каталог 
    if (($file == '.') || ($file == '..')) continue;

    $file_ref = "$folder\\$file"; //Получаем полный путь к файлу
    if (is_dir($file_ref)) { continue;  }// Если это каталог 
    else{ //  Если это файл, считываем, обрабатываем  
        fnmatch("*.xml", $file) or exit("Неправильное расширение файла $file !");
        $smpl_xml=simplexml_load_file($file_ref);
        break;//достаточно одной итерации!
    }
}

$pos = strrpos($file, ".");
$bookName = substr($file, 0, $pos);//имя исходного файла без расширения как имя книги!
$bookName = iconv("windows-1251", "UTF-8", $bookName);
$bookName = "Отчет \"$bookName\"";

//проверим, есть ли вложенные схемы
$ind=0;//количество вложенных схем <nestedSchema>

$kiDS = $smpl_xml->children();//1-й уровень
foreach($kiDS as $ma) {//дети: dataSource, nestedSchema, settingsVariant
    $aName = $ma->getName();//имя дочернего узла 
    if($aName=='nestedSchema'){$ind++;}
}

$masPages = array(); 
$masVarSettings = array();//ассоц массив вариантов отчета
$masChapters = array();//результирующий 3-х уровневый массив
$strA = ""; $strB = "";
$tempName = "";

//
if($ind>0){// есть вложенные схемы <nestedSchema> 
    
    $kiDS = $smpl_xml->children();//1-й уровень
    foreach($kiDS as $ma) {//дети: dataSource, nestedSchema, settingsVariant
        $aName = $ma->getName();

        if($aName=='dataSource'){continue;}
        elseif($aName=='nestedSchema'){//ВЛОЖЕННАЯ СХЕМА
            $aNameName = $ma->name; //имя вложенной схемы

            $kids = $ma->children();//2-й уровень <nestedSchema>
            foreach($kids as $mb) {//дети: <name>, <title>, <schema>, <settings>
                $bName = $mb->getName();

                if($bName=='name'){$keyP = (string)$mb; }
                elseif($bName=='schema'){ 

                    $kid = $mb->children();//3-й уровень <schema>
                    foreach($kid as $mc) {//дети: <dataSource>, <dataSet>, <calculatedField>, <totalField>, 
, <settingsVariant>
                        $cName = (string)$mc->getName();

                        if($cName=='dataSource'){continue;}  
                        elseif($cName=='dataSet'){//дети: <name>, <field>, <dataSource>, <query>
                            if($cName != $tempName){//защелка 
                                $tempName = $cName; 

                                foreach ($kid->$cName as $md){//4-й уровень <dataSet>---дети: <name>, <field>, <dataSource>, <query> 
                                    $dName = (string)$md->name;
        
                                    foreach ($md->field as $fi){
                                        $strA = ($fi->asXML()."\r\n\t\t\t\t");
                                        $strB = $strB.$strA; 
                                    }
                                    $keyA = $dName."_field";
                                    if($strB){$masPages[$keyA] = $strB; $strB = "";}
                    
                                    foreach ($md->query as $qu){

                                        $strA = ($qu->asXML()."\r\n\t\t\t\t");
                                        $strB = $strB.$strA; 
                                    }
                                    $keyB = $dName."_query";
                                    if($strB){$masPages[$keyB] = $strB; $strB = "";}

                                }//foreach  4-й уровень
                            }//if
                        }//'dataSet'
                        //
                        elseif($cName != $tempName){//<calculatedField>, <totalField>, 
, <settingsVariant> и тд.
                            $tempName = $cName;/*защелка*/ 

                            foreach($kid->$cName as $cс){//по одноименным узлам
                                $strA = ($cс->asXML()."\r\n\t\t\t\t");
                                $strB = $strB.$strA; 
                            }
                            if($strB){$masPages[$cName] = $strB; $strB = "";}
                        }

                    }//foreach(schema)  3-й уровень

                    $keyName = "$aNameName.$bName";
                    $masChapters[$keyName] = $masPages;

                }//'schema'          
                elseif($bName=='settings'){ 
                    $elem = ($mb->asXML()."\r\n\t\t\t\t");
                    $masPages[$bName] = $elem;//массив строк в свою страницу
                }//'settings'

                $masChapters["$aNameName"] = $masPages; $masPages = false;

            }//foreach(nestedSchema) 2-й уровень

        }//'nestedSchema'
        // 
        elseif($aName=='settingsVariant'){//ВАРИАНТЫ НАСТРОЕК ОТЧЕТА
            
            $namespaces = $smpl_xml->$aName->getNameSpaces(true);
            $nn = $ma->children($namespaces['dcsset']);
            $key = (string)$nn->name; //имя (заголовок) страницы 
        
            $elem = ($ma->asXML()."\r\n\t\t\t\t");
            $masVarSettings[$key] = $elem;//массив строк в свою страницу
        }//'settingsVariant'

    }//foreach($smpl_xml) 1-й уровень

    $key = "ВариантыНастроекОтчета";
    $masChapters[$key] = $masVarSettings; $masVarSettings = false;

    print_r($masChapters);  

       
}//есть вложенные схемы
else{//нет вложенных схем

    $ee = (string)$smpl_xml->dataSet->attributes('xsi',true)->type;//определим тип узла через его атрибут
        
    if($ee ==='DataSetUnion'){//несколько наборов данных

        echo "нет вложенных схем, несколько наборов данных \n";
        $tempName = "";
        
        $kiDS = $smpl_xml->children();//1-й уровень
        foreach($kiDS as $ma) {//дети: dataSource, dataSet, calculatedField, totalField, parameter и тд settingsVariants
            $nodeName = $ma->getName();//имя дочернего узла 

            if($nodeName == 'dataSource'){ continue; }
            elseif($nodeName == 'dataSet'){//БОЛЬШАЯ ТАБЛИЦА, ЗАПРОС

                $kids = $ma->children();//2-й уровень
                foreach($kids as $mb) {//дети: name, field, item
                    $nName = $mb->getName();//имя дочернего узла 

                    if($nName=='name'){                 
                        $keyP = (string)$kids->$nName;//<dataSet><name>ДоходыИРасходы</name>
                    }
                    elseif($nName=='field'){            
                        //БОЛЬШАЯ ТАБЛИЦА 1
                        if($nName != $tempName){//защелка 
                            $tempName = $nName;

                            foreach ($kids->$nName as $cс){
                                $strA = ($cс->asXML()."\r\n\t\t\t\t");
                                $strB = $strB.$strA; 
                            } 
                            $keyG = $keyP."_$nName";
                            if($strB){$masPages[$keyG] = $strB; $strB = "";}
                        }
                    }
                    elseif($nName=='item'){

                        if($nName != $tempName){//защелка 
                            $tempName = $nName;

                            foreach ($kids->$nName as $it){ 

                                $itName = (string)$it->name;
        
                                foreach ($it->field as $fi){
                                    $strA = ($fi->asXML()."\r\n\t\t\t\t");
                                    $strB = $strB.$strA; 
                                }
                                $keyA = $itName."_field";
                                if($strB){$masPages[$keyA] = $strB; $strB = "";}
                    
                                foreach ($it->query as $qu){
                                    $strA = ($qu->asXML()."\r\n\t\t\t\t");
                                    $strB = $strB.$strA; 
                                }
                                $keyB = $itName."_query";
                                if($strB){$masPages[$keyB] = $strB; $strB = "";}

                            }//foreach
                        }//if           
                    }//elseif
                }//foreach

            }//'dataSet'
            //
            elseif($nodeName == 'settingsVariant'){//ВАРИАНТЫ НАСТРОЕК ОТЧЕТА

                $namespaces = $smpl_xml->$nodeName->getNameSpaces(true);
                $nn = $ma->children($namespaces['dcsset']);
                $key = (string)$nn->name; //имя (заголовок) страницы 
                                
                $elem = ($ma->asXML()."\r\n\t\t\t\t");
                $masVarSettings[$key] = $elem;//массив строк в свою страницу

            }
            //
            elseif($nodeName != $tempName){//ВЫЧИСЛЯЕМЫЕ ПОЛЯ, РЕСУРСЫ, ПАРАМЕТРЫ И ТД.
                $tempName = $nodeName;
                foreach ($smpl_xml->$nodeName as $cс){//по одноименным узлам
    
                    $strA = ($cс->asXML()."\r\n\t\t\t\t");
                    $strB = $strB.$strA; 
                }
                if($strB){$masPages[$nodeName] = $strB; $strB = "";}
            }

       }//foreach ($kiDS)     

    }//if('DataSetUnion')несколько наборов данных
    else{//один набор данных
        echo "нет вложенных схем, один набор данных";
        $tempName = "";

        $kiDS = $smpl_xml->children();//1-й уровень
        foreach($kiDS as $ma) {//дети: dataSource, dataSet, calculatedField, totalField, parameter и тд settingsVariants
            $nodeName = $ma->getName();//имя дочернего узла 

            if($nodeName == 'dataSource'){ continue; }
            elseif($nodeName == 'dataSet'){//БОЛЬШАЯ ТАБЛИЦА, ЗАПРОС

                $kids = $ma->children();//2-й уровень
                foreach($kids as $mb){//дети: name, field, dataSource, query
                    $nName = $mb->getName();//имя дочернего узла 
                                        
                    if($nName=='name'){
                        $keyA = (string)$kids->$nName;//<dataSet><name>СвободныеОстатки</name>
                    }
                    elseif($nName=='field'){  

                        if($nName != $tempName){//защелка 
                            $tempName = $nName;
                            foreach ($kids->$nName as $cс){

                                $strA = ($cс->asXML()."\r\n\t\t\t\t");
                                $strB = $strB.$strA; 
                            } 
                            $keyG = $keyA."_$nName";
                            if($strB){$masPages[$keyG] = $strB; $strB = "";}
                        }
                    }
                    elseif($nName=='dataSource'){ continue; }
                    elseif($nName=='query'){  

                        $strA = ($mb->asXML()."\r\n\t\t\t\t");
                        $strB = $strB.$strA; 
                        $keyG = $keyA."_$nName";
                        if($strB){$masPages[$keyG] = $strB; $strB = "";}
                    }
                }

            }//'dataSet'
            //
            elseif($nodeName == 'settingsVariant'){//ВАРИАНТЫ НАСТРОЕК ОТЧЕТА

                $namespaces = $smpl_xml->$nodeName->getNameSpaces(true);
                $nn = $ma->children($namespaces['dcsset']);
                $key = (string)$nn->name; //имя (заголовок) страницы 
        
                $elem = ($ma->asXML()."\r\n\t\t\t\t");
                $masVarSettings[$key] = $elem;//массив строк в свою страницу
            }
            //
            elseif($nodeName != $tempName){//ВЫЧИСЛЯЕМЫЕ ПОЛЯ, РЕСУРСЫ, ПАРАМЕТРЫ И ТД.
                $tempName = $nodeName;
                foreach ($smpl_xml->$nodeName as $cс){//по одноименным узлам
    
                    $strA = ($cс->asXML()."\r\n\t\t\t\t");
                    $strB = $strB.$strA; 
                }
                if($strB){$masPages[$nodeName] = $strB; $strB = "";}
            }
                        
        }//foreach ($kiDS)
    }//else один набор данных

    $key = (string)$smpl_xml->dataSet->name; 
    $masChapters[$key] = $masPages; $masPages = false;

    $key = "ВариантыНастроекОтчета";
    $masChapters[$key] = $masVarSettings; $masVarSettings = false;


}//else нет вложенных схем
//Просканируем полученный массив данных:
//showAssocMassiv($masChapters);
//print_r($masChapters);

// $masTotalRefList - ассоц масив со списками ссылок на страницы текущей главы.  
$masTotalRefList = masTotalRefList($masChapters);
//print_r($masTotalRefList);

$fileName = "to1/Obzor1.htm";//$fileName - имя 2-й страницы книги с путем  "to1/Obzor1.htm" 
$fileName2 = "to1/index.htm";//$fileName - имя 1-й страницы книги с путем  "to1/index.htm" 

/*
$masChapters - исходный массив данных
$masTotalRefList - ассоц масив со списками ссылок на страницы текущей главы.
*/
makePrimSecondCurrentObzorPage($masChapters, $masTotalRefList, $fileName, $bookName);

makeIndexPage($fileName2, $bookName);


//=======================================================
//=======================================================
//=======================================================
?>

Обновлено 10.04.2016 03:56