Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parsing QGIS Project with PHP XMLReader instead of DOM #4819

Merged
merged 48 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
7ba9de2
\Lizmap\App\XmlTools Docstring
rldhont Nov 3, 2023
f0de082
Enhancing \Lizmap\App\XmlTools to get \XMLReader object
rldhont Nov 3, 2023
6a18ce6
Create QgisProjectParser to try parsing with \XMLReader
rldhont Oct 25, 2023
8380aca
QgisProjectParser -> Lizmap\Project\Qgis\Parser
rldhont Sep 20, 2024
3e2af62
Lizmap\Project\Qgis\BaseQgisObject class
rldhont Nov 8, 2023
9a6acec
Lizmap\Project\Qgis\BaseQgisXmlObject class
rldhont Nov 16, 2023
61f6ceb
New Lizmap\Project\Qgis\SpatialRefSys for QGIS Spatial Reference Syst…
rldhont Nov 7, 2023
0240835
New Lizmap\Project\Qgis\ProjectGuiProperties for QGIS Project Gui Pro…
rldhont Nov 8, 2023
fe9a795
New Lizmap\Project\Qgis\ProjectVariables for QGIS Project Variables
rldhont Nov 10, 2023
91ee57a
New Lizmap\Project\Qgis\ProjectProperties for QGIS Project Properties
rldhont Nov 8, 2023
efd77a6
new Lizmap\Project\Qgis\LayerTree* classes
rldhont Nov 16, 2023
d1820dd
new Lizmap\Project\Qgis\Layout\* classes
rldhont Nov 30, 2023
f90b9d1
new Lizmap\Project\Qgis\Layer\* classes
rldhont Oct 15, 2024
65913b4
new Lizmap\Project\Qgis\ProjectVisibilityPreset and ProjectVisibility…
rldhont Nov 30, 2023
f26e049
New Lizmap\Project\Qgis\ProjectRelation for QGIS Project Relation
rldhont Mar 22, 2024
638da9b
New Lizmap\Project\Qgis\Layer\EditWidget\* classes and Project\Qgis\L…
rldhont Dec 4, 2023
b075c57
Lizmap\Project\Qgis\Layer\VectorLayerField parsing EditWidget
rldhont Mar 23, 2024
4ee625c
Lizmap\Project\Qgis\Layer\VectorLayer methods toKeyArray and getFormC…
rldhont Oct 15, 2024
6849f10
New Lizmap\Project\Qgis\ProjectInfo for QGIS Project Info
rldhont Mar 22, 2024
a5cfb47
Lint QgisProject
rldhont Sep 18, 2024
e45767d
PHP: move getLayersWithLabels method form Project to ProjectConfig
rldhont Sep 27, 2024
59eb93f
Using Lizmap\Project\Qgis\ProjectInfo in QgisProject::readXmlProject
rldhont Sep 18, 2024
d8b37b1
Using Lizmap\Project\Qgis\ProjectInfo in QgisProject::getPrintTemplates
rldhont Sep 18, 2024
ff347e8
Using Lizmap\Project\Qgis\ProjectInfo in QgisProject::readLocateByLayer
rldhont Sep 18, 2024
6fe5728
Using Lizmap\Project\Qgis\ProjectInfo in QgisProject::readEditionLayers
rldhont Sep 18, 2024
5b7e155
Using Lizmap\Project\Qgis\ProjectInfo in QgisProject::readEditionForms
rldhont Sep 18, 2024
1b94029
Using Lizmap\Project\Qgis\ProjectInfo in QgisProject::readAttributeLa…
rldhont Sep 18, 2024
6a780e6
Using Lizmap\Project\Qgis\ProjectInfo in QgisProject::setShortNames
rldhont Sep 18, 2024
263ffa1
Using Lizmap\Project\Qgis\ProjectInfo in QgisProject::setLayerOpacity
rldhont Sep 18, 2024
c6782dd
Using Lizmap\Project\Qgis\ProjectInfo in QgisProject::unsetPropAfterRead
rldhont Sep 18, 2024
1214f03
Using Lizmap\Project\Qgis\ProjectInfo in QgisProject::setLayerGroupData
rldhont Sep 18, 2024
613be7b
Using Lizmap\Project\Qgis\ProjectInfo in QgisProject::setLayerShowFea…
rldhont Sep 18, 2024
7cffcc1
Lint Lizmap\Project\Project readLayersOrder method
rldhont Sep 20, 2024
edf508c
Using Lizmap\Project\Qgis\ProjectInfo in QgisProject::readLayersOrder
rldhont Sep 20, 2024
cc9cb92
Using Lizmap\Project\Qgis\ProjectInfo in QgisProject::readLayersLabel…
rldhont Sep 29, 2024
d562ba4
Tests PHP: QgisProject does not use DOM
rldhont Sep 29, 2024
0aadf3a
Lint QgisProject after changes
rldhont Oct 1, 2024
967a143
QgisProject remove unnecessary methods
rldhont Oct 1, 2024
0ba63b2
QgisProject remove code in setPropertiesAfterRead methods
rldhont Oct 4, 2024
5dbc1c7
QgisProject remove code in read methods
rldhont Oct 4, 2024
3c9970b
QgisProject deprecated methods
rldhont Oct 4, 2024
250d76d
Update Print component
rldhont Oct 8, 2024
afe2934
Update legacy switcher layers actions
rldhont Oct 8, 2024
35ad740
Update feature toolbar
rldhont Oct 8, 2024
389f403
Tests e2e webdav: relative path
rldhont Oct 14, 2024
4ad59dd
new Lizmap\Project\Qgis\Layer\RasterLayer* classes
rldhont Nov 15, 2024
59e7b9d
Methods to load embedded project and layer, and a method to get layer…
rldhont Dec 2, 2024
c39b171
Use App\XmlTools::xmlReaderFromFile in ProjectMainData
rldhont Jan 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion assets/src/components/FeatureToolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,8 @@ export default class FeatureToolbar extends HTMLElement {
this._layouts = mainLizmap.config?.layouts;

mainLizmap.config?.printTemplates.map((template, index) => {
if (this._layerId === template?.atlas?.coverageLayer && template?.atlas?.enabled === '1') {
if (this._layerId === template?.atlas?.coverageLayer
&& (template?.atlas?.enabled === '1' || template?.atlas?.enabled === true)) {
// Lizmap >= 3.7
if (mainLizmap.config?.layouts?.list) {
if (mainLizmap.config?.layouts?.list?.[index]?.enabled) {
Expand Down
2 changes: 1 addition & 1 deletion assets/src/components/Print.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export default class Print extends HTMLElement {
// Filtering printTemplates by atlas enabled
// and since 3.7 by layout enabled
mainLizmap.config?.printTemplates.map((template, index) => {
if (template?.atlas?.enabled === '0'){
if (template?.atlas?.enabled === '0' || template?.atlas?.enabled === false){
// Lizmap >= 3.7
if (layouts?.list) {
if(layouts.list?.[index]?.enabled){
Expand Down
25 changes: 25 additions & 0 deletions assets/src/legacy/attributeTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -1781,6 +1781,31 @@ var lizAttributeTable = function() {
&& config.attributeLayers[aName]['attributetableconfig']
&& !$.isEmptyObject(config.attributeLayers[aName]['attributetableconfig']['columns'])
){
if (!('column' in config.attributeLayers[aName]['attributetableconfig']['columns'])) {
var atc = config.attributeLayers[aName]['attributetableconfig']['columns'];
if(atc.length == 0){
return colToReturn;
}
var lizcols = columns.slice(0, firstDisplayedColIndex);
var newcolumns = [];
for (var x in atc) {
var colx = atc[x];
// Do nothing if the item does not reference a field
if (colx.type != 'field') {
continue;
}
for (const column of columns) {
if (!('data' in column)) {
continue;
}
if (colx.name == column.data) {
newcolumns.push(column);
}
}
}
colToReturn['columns'] = lizcols.concat(newcolumns);
return colToReturn;
}
var atc = config.attributeLayers[aName]['attributetableconfig']['columns']['column'];
if(atc.length == 0){
return colToReturn;
Expand Down
2 changes: 1 addition & 1 deletion assets/src/legacy/switcher-layers-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ var lizLayerActionButtons = function() {
}

layerOrGroup.checked = true;
layerOrGroup.expanded = layerParams?.expanded === "1";
layerOrGroup.expanded = layerParams?.expanded === "1" || layerParams?.expanded === true;

// `symbologyChildren` is empty for some time if the theme switches
// the layer style from simple to categorized.
Expand Down
95 changes: 82 additions & 13 deletions lizmap/modules/lizmap/lib/App/XmlTools.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@

class XmlTools
{
/*
* Interprets a string of XML into an object
/**
* Interprets a string of XML into an object.
*
* @param string $xml_str a well-formed XML string
*
* @return SimpleXmlElement|string an object of class SimpleXMLElement with properties
* containing the data held within the XML document, or
* a string containing the error message.
* @return \SimpleXmlElement|string an object of class SimpleXMLElement with properties
* containing the data held within the XML document, or
* a string containing the error message
*/
public static function xmlFromString($xml_str)
{
Expand All @@ -34,14 +34,14 @@ public static function xmlFromString($xml_str)
return $xml;
}

/*
* Interprets an XML file into an object
/**
* Interprets an XML file into an object.
*
* @param string $xml_path the path to the xml file
*
* @return SimpleXmlElement|string an object of class SimpleXMLElement with properties
* containing the data held within the XML document, or
* a string containing the error message.
* @return \SimpleXmlElement|string an object of class SimpleXMLElement with properties
* containing the data held within the XML document, or
* a string containing the error message
*/
public static function xmlFromFile($xml_path)
{
Expand All @@ -54,12 +54,12 @@ public static function xmlFromFile($xml_path)
return $xml;
}

/*
* Get XML error message
/**
* Get XML error message.
*
* Build an error message based on LibXMLError object
*
* @return string the error message.
* @return string the error message
*/
private static function xmlErrorMsg()
{
Expand Down Expand Up @@ -89,7 +89,76 @@ private static function xmlErrorMsg()
$msg .= 'Column: '.$error->column.' ';
$msg .= trim($error->message);
}
// Clear libxml error buffer
libxml_clear_errors();

return $msg;
}

/**
* Interprets a string of XML into an XML Pull parser.
* It acts as a cursor going forward on the document stream and stopping at each node on the way.
*
* @param string $xml_str a well-formed XML string
*
* @return \XMLReader an object of class XMLReader with properties at the root document element
* containing the data held within the XML document
*/
public static function xmlReaderFromString($xml_str)
{
$oXml = new \XMLReader();
// Set XML
if (!$oXml->XML($xml_str)) {
throw new \Exception(self::xmlErrorMsg());
}

// Read until we are at the root document element
while ($oXml->read()) {
if ($oXml->nodeType == \XMLReader::ELEMENT
&& $oXml->depth == 0) {
break;
}
}

$errorMsg = self::xmlErrorMsg();
if ($errorMsg !== '') {
throw new \Exception($errorMsg);
}

return $oXml;
}

/**
* Interprets an XML file into an XML pull parser.
* It acts as a cursor going forward on the document stream and stopping at each node on the way.
*
* @param string $xml_path the path to the xml file
*
* @return \XMLReader an object of class XMLReader with properties at the root document element
* containing the data held within the XML document
*/
public static function xmlReaderFromFile($xml_path)
{
$oXml = new \XMLReader();

// Open file
if (!$oXml->open($xml_path)) {
throw new \Exception(self::xmlErrorMsg());
}

// Read until we are at the root document element
while ($oXml->read()) {
if ($oXml->nodeType == \XMLReader::ELEMENT
&& $oXml->depth == 0) {
break;
}
}

$errorMsg = self::xmlErrorMsg();
if ($errorMsg !== '') {
throw new \Exception($errorMsg);
}

return $oXml;
}
}
35 changes: 2 additions & 33 deletions lizmap/modules/lizmap/lib/Project/Project.php
Original file line number Diff line number Diff line change
Expand Up @@ -261,36 +261,7 @@ protected function readProject()
*/
protected function getLayersWithLabels()
{
// Keep a list of layer ids for which to replace the code by labels
$layersWithLabeledFields = array();

// Attribute layers
foreach ($this->cfg->getAttributeLayers() as $key => $config) {
if ($config->hideLayer == 'True') {
continue;
}
$layersWithLabeledFields[] = $config->layerId;
}

// Dataviz layers
foreach ($this->cfg->getDatavizLayers() as $o => $config) {
$layerId = $config->layerId;
if (array_key_exists($layerId, $layersWithLabeledFields)) {
continue;
}
$layersWithLabeledFields[] = $config->layerId;
}

// Form filter layers
foreach ($this->cfg->getFormFilterLayers() as $o => $config) {
$layerId = $config->layerId;
if (array_key_exists($layerId, $layersWithLabeledFields)) {
continue;
}
$layersWithLabeledFields[] = $config->layerId;
}

return $layersWithLabeledFields;
return $this->cfg->getLayersWithLabels();
}

public function getQgisPath()
Expand Down Expand Up @@ -1757,13 +1728,11 @@ protected function readAttributeLayers(QgisProject $xml, ProjectConfig $cfg)
}

/**
* @param \SimpleXMLElement $xml
*
* @return int[]
*/
protected function readLayersOrder(QgisProject $xml)
{
return $this->qgis->readLayersOrder($xml, $this->getLayers());
return $xml->readLayersOrder($this->cfg->getLayers());
}

/**
Expand Down
43 changes: 43 additions & 0 deletions lizmap/modules/lizmap/lib/Project/ProjectConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,49 @@ public function getDatavizLayers()
return $this->datavizLayers;
}

/**
* List of the layers configured in the tools
* Attribute table, form filter & dataviz.
*
* We use this list to find all the fields for which
* we need to replace the code by their corresponding labels
*
* @return array<string> Array of layer ids
*/
public function getLayersWithLabels()
{
// Keep a list of layer ids for which to replace the code by labels
$layersWithLabeledFields = array();

// Attribute layers
foreach ($this->getAttributeLayers() as $key => $config) {
if ($config->hideLayer == 'True') {
continue;
}
$layersWithLabeledFields[] = $config->layerId;
}

// Dataviz layers
foreach ($this->getDatavizLayers() as $o => $config) {
$layerId = $config->layerId;
if (array_key_exists($layerId, $layersWithLabeledFields)) {
continue;
}
$layersWithLabeledFields[] = $config->layerId;
}

// Form filter layers
foreach ($this->getFormFilterLayers() as $o => $config) {
$layerId = $config->layerId;
if (array_key_exists($layerId, $layersWithLabeledFields)) {
continue;
}
$layersWithLabeledFields[] = $config->layerId;
}

return $layersWithLabeledFields;
}

/** Get the HTML template built from the Drag and drop layout
* and override the original datavizTemplate configuration option.
*
Expand Down
49 changes: 6 additions & 43 deletions lizmap/modules/lizmap/lib/Project/ProjectMainData.php
Original file line number Diff line number Diff line change
Expand Up @@ -244,53 +244,16 @@ public function getData()
*/
protected function readXmlProject($qgs_path)
{
$oXml = new \XMLReader();

// Open file
if (!$oXml->open($qgs_path)) {
throw new UnknownLizmapProjectException('The file '.$qgs_path.' cannot be parsed.');
}
$xmlReader = App\XmlTools::xmlReaderFromFile($qgs_path);

$data = array();
// Read until we are at the root document element
while ($oXml->read()) {
if ($oXml->nodeType == \XMLReader::ELEMENT
&& $oXml->depth == 1
&& $oXml->localName == 'properties') {
$data = array_merge($data, $this->readXmlProperties($oXml));
}
}
$errorMsg = '';
foreach (libxml_get_errors() as $error) {
if ($errorMsg !== '') {
$errorMsg .= '\n';
while ($xmlReader->read()) {
if ($xmlReader->nodeType == \XMLReader::ELEMENT
&& $xmlReader->depth == 1
&& $xmlReader->localName == 'properties') {
$data = array_merge($data, $this->readXmlProperties($xmlReader));
}

switch ($error->level) {
case LIBXML_ERR_WARNING:
$errorMsg .= 'Warning '.$error->code.': ';

break;

case LIBXML_ERR_ERROR:
$errorMsg .= 'Error '.$error->code.': ';

break;

case LIBXML_ERR_FATAL:
$errorMsg .= 'Fatal Error '.$error->code.': ';

break;
}
$errorMsg .= 'Line: '.$error->line.' ';
$errorMsg .= 'Column: '.$error->column.' ';
$errorMsg .= trim($error->message);
}
// Clear libxml error buffer
libxml_clear_errors();

if ($errorMsg !== '') {
throw new \Exception($errorMsg);
}

return $data;
Expand Down
Loading
Loading