mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
N°6974 - Flatten classes in datamodel - Allow _delta="merge" in strict mode
This commit is contained in:
@@ -339,6 +339,26 @@ class DesignElement extends \DOMElement
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if the node is contained in a _delta="merge" tree
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function IsInSpecifiedMerge(): bool
|
||||||
|
{
|
||||||
|
// Iterate through the parents: reset the flag if any of them has a flag set
|
||||||
|
for ($oParent = $this; $oParent instanceof MFElement; $oParent = $oParent->parentNode) {
|
||||||
|
$sDeltaSpec = $oParent->getAttribute('_delta');
|
||||||
|
if ($sDeltaSpec === 'merge') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (in_array($sDeltaSpec, ['define', 'define_if_not_exists', 'force', 'redefine'])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the child node matching the given node.
|
* Find the child node matching the given node.
|
||||||
* UNSAFE: may return nodes marked as _alteration="removed"
|
* UNSAFE: may return nodes marked as _alteration="removed"
|
||||||
|
|||||||
@@ -832,6 +832,7 @@ class ModelFactory
|
|||||||
case '':
|
case '':
|
||||||
$bMustExist = ($sDeltaSpec === 'must_exist');
|
$bMustExist = ($sDeltaSpec === 'must_exist');
|
||||||
$bIfExists = ($sDeltaSpec === 'if_exists');
|
$bIfExists = ($sDeltaSpec === 'if_exists');
|
||||||
|
$bSpecifiedMerge = $oSourceNode->IsInSpecifiedMerge();
|
||||||
|
|
||||||
/** @var MFElement $oTargetNode */
|
/** @var MFElement $oTargetNode */
|
||||||
$oTargetNode = $oTargetParentNode->_FindChildNode($oSourceNode, $sSearchId);
|
$oTargetNode = $oTargetParentNode->_FindChildNode($oSourceNode, $sSearchId);
|
||||||
@@ -847,7 +848,7 @@ class ModelFactory
|
|||||||
// Do not continue deeper
|
// Do not continue deeper
|
||||||
$oTargetNode = null;
|
$oTargetNode = null;
|
||||||
} else {
|
} else {
|
||||||
if ($sMode === self::LOAD_DELTA_MODE_STRICT && ($sSearchId !== '' || is_null($oSourceNode->firstElementChild))) {
|
if (!$bSpecifiedMerge && $sMode === self::LOAD_DELTA_MODE_STRICT && ($sSearchId !== '' || is_null($oSourceNode->firstElementChild))) {
|
||||||
$iLine = ModelFactory::GetXMLLineNumber($oSourceNode);
|
$iLine = ModelFactory::GetXMLLineNumber($oSourceNode);
|
||||||
$sItopNodePath = DesignDocument::GetItopNodePath($oSourceNode);
|
$sItopNodePath = DesignDocument::GetItopNodePath($oSourceNode);
|
||||||
throw new MFException($sItopNodePath.' at line '.$iLine.': could not be found or marked as removed (strict mode)',
|
throw new MFException($sItopNodePath.' at line '.$iLine.': could not be found or marked as removed (strict mode)',
|
||||||
@@ -867,12 +868,15 @@ class ModelFactory
|
|||||||
// Do not continue deeper everything is already copied
|
// Do not continue deeper everything is already copied
|
||||||
$oTargetNode = null;
|
$oTargetNode = null;
|
||||||
} else {
|
} else {
|
||||||
// copy the node with attributes and continue deeper
|
// copy the node with attributes (except _delta) and continue deeper
|
||||||
$oTargetNode = $oTargetDocument->importNode($oSourceNode, false);
|
$oTargetNode = $oTargetDocument->importNode($oSourceNode, false);
|
||||||
foreach ($oSourceNode->attributes as $oAttributeNode) {
|
foreach ($oSourceNode->attributes as $oAttributeNode) {
|
||||||
$oTargetNode->setAttribute($oAttributeNode->name, $oAttributeNode->value);
|
$oTargetNode->setAttribute($oAttributeNode->name, $oAttributeNode->value);
|
||||||
}
|
}
|
||||||
if ($sSearchId !== '') {
|
if ($oTargetNode->hasAttribute('_delta')) {
|
||||||
|
$oTargetNode->removeAttribute('_delta');
|
||||||
|
}
|
||||||
|
if ($sSearchId !== '' || $bSpecifiedMerge) {
|
||||||
// Add the node by default
|
// Add the node by default
|
||||||
$oTargetParentNode->AddChildNode($oTargetNode);
|
$oTargetParentNode->AddChildNode($oTargetNode);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -75,10 +75,12 @@ class ModelFactoryTest extends ItopTestCase
|
|||||||
// Canonicalize the expected XML (to cope with indentation)
|
// Canonicalize the expected XML (to cope with indentation)
|
||||||
$oExpectedDocument = new DOMDocument();
|
$oExpectedDocument = new DOMDocument();
|
||||||
$oExpectedDocument->preserveWhiteSpace = false;
|
$oExpectedDocument->preserveWhiteSpace = false;
|
||||||
$oExpectedDocument->loadXML($sXML);
|
|
||||||
$oExpectedDocument->formatOutput = true;
|
$oExpectedDocument->formatOutput = true;
|
||||||
|
$oExpectedDocument->loadXML($sXML);
|
||||||
|
|
||||||
return $oExpectedDocument->C14N(false, true);
|
$sSavedXML = $oExpectedDocument->SaveXML();
|
||||||
|
|
||||||
|
return str_replace(' encoding="UTF-8"', '', $sSavedXML);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -665,7 +667,7 @@ class ModelFactoryTest extends ItopTestCase
|
|||||||
$oFactory = $this->MakeVanillaModelFactory($sInitialXML);
|
$oFactory = $this->MakeVanillaModelFactory($sInitialXML);
|
||||||
$oFactoryDocument = $this->GetNonPublicProperty($oFactory, 'oDOMDocument');
|
$oFactoryDocument = $this->GetNonPublicProperty($oFactory, 'oDOMDocument');
|
||||||
$sExpectedXML = null;
|
$sExpectedXML = null;
|
||||||
if (\utils::StartsWith($sExpectedXMLOrErrorMessage, '<')) {
|
if (\utils::StartsWith(trim($sExpectedXMLOrErrorMessage), '<')) {
|
||||||
$sExpectedXML = $sExpectedXMLOrErrorMessage;
|
$sExpectedXML = $sExpectedXMLOrErrorMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3026,14 +3028,16 @@ XML
|
|||||||
,
|
,
|
||||||
],
|
],
|
||||||
'Conditionally deleted class' => [
|
'Conditionally deleted class' => [
|
||||||
'sInitialXMLInternal' => '<itop_design>
|
'sInitialXMLInternal' => '
|
||||||
|
<itop_design>
|
||||||
<classes>
|
<classes>
|
||||||
<class id="cmdbAbstractObject"/>
|
<class id="cmdbAbstractObject"/>
|
||||||
<class id="C_1_1" _alteration="removed"/>
|
<class id="C_1_1" _alteration="removed"/>
|
||||||
<class id="C_1" _alteration="remove_needed"/>
|
<class id="C_1" _alteration="remove_needed"/>
|
||||||
</classes>
|
</classes>
|
||||||
</itop_design>',
|
</itop_design>',
|
||||||
'sExpectedXMLDelta' => '<itop_design>
|
'sExpectedXMLDelta' => '
|
||||||
|
<itop_design>
|
||||||
<classes>
|
<classes>
|
||||||
<class id="C_1_1" _delta="delete"/>
|
<class id="C_1_1" _delta="delete"/>
|
||||||
<class id="C_1" _delta="delete_if_exists"/>
|
<class id="C_1" _delta="delete_if_exists"/>
|
||||||
@@ -3411,15 +3415,21 @@ XML
|
|||||||
$oDocument->loadXML($sDeltaXML);
|
$oDocument->loadXML($sDeltaXML);
|
||||||
/* @var MFElement $oDeltaRoot */
|
/* @var MFElement $oDeltaRoot */
|
||||||
$oDeltaRoot = $oDocument->firstChild;
|
$oDeltaRoot = $oDocument->firstChild;
|
||||||
|
$sExpectedXML = null;
|
||||||
|
if (\utils::StartsWith(trim($sExpectedXMLInLaxMode), '<')) {
|
||||||
|
$sExpectedXML = $sExpectedXMLInLaxMode;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
$oFactory->LoadDelta($oDeltaRoot, $oFactoryDocument, ModelFactory::LOAD_DELTA_MODE_LAX);
|
$oFactory->LoadDelta($oDeltaRoot, $oFactoryDocument, ModelFactory::LOAD_DELTA_MODE_LAX);
|
||||||
$this->AssertEqualModels($sExpectedXMLInLaxMode, $oFactory, 'LoadDelta(lax) did not produce the expected result');
|
$this->assertNotNull($sExpectedXML, "LoadDelta(lax) should have failed with exception: $sExpectedXMLInLaxMode");
|
||||||
|
$this->AssertEqualModels($sExpectedXML, $oFactory, 'LoadDelta(lax) did not produce the expected result');
|
||||||
}
|
}
|
||||||
catch (ExpectationFailedException $e) {
|
catch (ExpectationFailedException $e) {
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
catch (\Exception $e) {
|
catch (\Exception $e) {
|
||||||
$this->assertNull($sExpectedXMLInLaxMode, 'LoadDelta(lax) should not have failed with exception: '.$e->getMessage());
|
$this->assertNull($sExpectedXML, 'LoadDelta(lax) should not have failed with exception: '.$e->getMessage());
|
||||||
|
$this->assertEquals($sExpectedXMLInLaxMode, $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load in Strict mode
|
// Load in Strict mode
|
||||||
@@ -3430,118 +3440,233 @@ XML
|
|||||||
$oDocument->loadXML($sDeltaXML);
|
$oDocument->loadXML($sDeltaXML);
|
||||||
/* @var MFElement $oDeltaRoot */
|
/* @var MFElement $oDeltaRoot */
|
||||||
$oDeltaRoot = $oDocument->firstChild;
|
$oDeltaRoot = $oDocument->firstChild;
|
||||||
|
$sExpectedXML = null;
|
||||||
|
if (\utils::StartsWith(trim($sExpectedXMLInStrictMode), '<')) {
|
||||||
|
$sExpectedXML = $sExpectedXMLInStrictMode;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
$oFactory->LoadDelta($oDeltaRoot, $oFactoryDocument, ModelFactory::LOAD_DELTA_MODE_STRICT);
|
$oFactory->LoadDelta($oDeltaRoot, $oFactoryDocument, ModelFactory::LOAD_DELTA_MODE_STRICT);
|
||||||
$this->AssertEqualModels($sExpectedXMLInStrictMode, $oFactory, 'LoadDelta(strict) did not produce the expected result');
|
$this->assertNotNull($sExpectedXML, "LoadDelta(lax) should have failed with exception: $sExpectedXMLInStrictMode");
|
||||||
|
$this->AssertEqualModels($sExpectedXML, $oFactory, 'LoadDelta(strict) did not produce the expected result');
|
||||||
}
|
}
|
||||||
catch (ExpectationFailedException $e) {
|
catch (ExpectationFailedException $e) {
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
catch (\Exception $e) {
|
catch (\Exception $e) {
|
||||||
$this->assertNull($sExpectedXMLInStrictMode, 'LoadDelta(strict) should not have failed with exception: '.$e->getMessage());
|
$this->assertNull($sExpectedXML, 'LoadDelta(strict) should not have failed with exception: '.$e->getMessage());
|
||||||
|
$this->assertEquals($sExpectedXMLInStrictMode, $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function LoadDeltaModeProvider()
|
public function LoadDeltaModeProvider()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'merge delta have different behavior depending on the mode' => [
|
'default no _delta have different behavior depending on the mode' => [
|
||||||
'sInitialXML' => '
|
'sInitialXML' => '
|
||||||
<itop_design>
|
<itop_design>
|
||||||
<nodeA>
|
<nodeA/>
|
||||||
</nodeA>
|
|
||||||
</itop_design>',
|
</itop_design>',
|
||||||
'sDeltaXML' => '<itop_design>
|
'sDeltaXML' => '
|
||||||
|
<itop_design>
|
||||||
<nodeA>
|
<nodeA>
|
||||||
<nodeB id="C_1">
|
<nodeB id="C_1">
|
||||||
<parent>cmdbAbstractObject</parent>
|
<parent>cmdbAbstractObject</parent>
|
||||||
</nodeB>
|
</nodeB>
|
||||||
</nodeA>
|
</nodeA>
|
||||||
</itop_design>',
|
</itop_design>',
|
||||||
'sExpectedXMLInLaxMode' => '<itop_design>
|
'sExpectedXMLInLaxMode' => '
|
||||||
|
<itop_design>
|
||||||
<nodeA>
|
<nodeA>
|
||||||
<nodeB id="C_1" _alteration="added">
|
<nodeB id="C_1" _alteration="added">
|
||||||
<parent>cmdbAbstractObject</parent>
|
<parent>cmdbAbstractObject</parent>
|
||||||
</nodeB>
|
</nodeB>
|
||||||
</nodeA>
|
</nodeA>
|
||||||
</itop_design>',
|
</itop_design>',
|
||||||
'sExpectedXMLInStrictMode' => null,
|
'sExpectedXMLInStrictMode' => '/itop_design/nodeA/nodeB[C_1] at line 4: could not be found or marked as removed (strict mode)',
|
||||||
],
|
],
|
||||||
|
|
||||||
'mode specified in delta takes precedence' => [
|
'mode specified in delta takes precedence' => [
|
||||||
'sInitialXML' => '
|
'sInitialXML' => '
|
||||||
<itop_design>
|
<itop_design>
|
||||||
<nodeA>
|
<nodeA/>
|
||||||
</nodeA>
|
|
||||||
</itop_design>',
|
</itop_design>',
|
||||||
'sDeltaXML' => '<itop_design load="strict">
|
'sDeltaXML' => '
|
||||||
|
<itop_design load="strict">
|
||||||
<nodeA>
|
<nodeA>
|
||||||
<nodeB id="C_1">
|
<nodeB id="C_1">
|
||||||
<parent>cmdbAbstractObject</parent>
|
<parent>cmdbAbstractObject</parent>
|
||||||
</nodeB>
|
</nodeB>
|
||||||
</nodeA>
|
</nodeA>
|
||||||
</itop_design>',
|
</itop_design>',
|
||||||
'sExpectedXMLInLaxMode' => null,
|
'sExpectedXMLInLaxMode' => '/itop_design/nodeA/nodeB[C_1] at line 4: could not be found or marked as removed (strict mode)',
|
||||||
'sExpectedXMLInStrictMode' => null,
|
'sExpectedXMLInStrictMode' => '/itop_design/nodeA/nodeB[C_1] at line 4: could not be found or marked as removed (strict mode)',
|
||||||
],
|
],
|
||||||
'merge leaf nodes have different behavior depending on the mode' => [
|
|
||||||
|
'default no _delta leaf nodes have different behavior depending on the mode' => [
|
||||||
'sInitialXML' => '
|
'sInitialXML' => '
|
||||||
<itop_design>
|
<itop_design>
|
||||||
<nodeA>Test</nodeA>
|
<nodeA>Test</nodeA>
|
||||||
</itop_design>',
|
</itop_design>',
|
||||||
'sDeltaXML' => '<itop_design>
|
'sDeltaXML' => '
|
||||||
|
<itop_design>
|
||||||
<nodeA>Taste</nodeA>
|
<nodeA>Taste</nodeA>
|
||||||
</itop_design>',
|
</itop_design>',
|
||||||
'sExpectedXMLInLaxMode' => '<itop_design>
|
'sExpectedXMLInLaxMode' => '
|
||||||
<nodeA _alteration="replaced">Taste</nodeA>
|
<itop_design>
|
||||||
|
<nodeA _alteration="replaced">Taste</nodeA>
|
||||||
</itop_design>',
|
</itop_design>',
|
||||||
'sExpectedXMLInStrictMode' => null,
|
'sExpectedXMLInStrictMode' => '/itop_design/nodeA at line 3: cannot be modified without _delta flag (strict mode)',
|
||||||
],
|
],
|
||||||
'merge existing leaf nodes without text have same behavior' => [
|
|
||||||
|
'default no _delta on existing leaf nodes without text have same behavior' => [
|
||||||
'sInitialXML' => '
|
'sInitialXML' => '
|
||||||
<itop_design>
|
<itop_design>
|
||||||
<nodeA/>
|
|
||||||
</itop_design>',
|
|
||||||
'sDeltaXML' => '<itop_design>
|
|
||||||
<nodeA/>
|
<nodeA/>
|
||||||
</itop_design>',
|
</itop_design>',
|
||||||
'sExpectedXMLInLaxMode' => '<itop_design>
|
'sDeltaXML' => '
|
||||||
<nodeA/>
|
|
||||||
</itop_design>',
|
|
||||||
'sExpectedXMLInStrictMode' => '<itop_design>
|
|
||||||
<nodeA/>
|
|
||||||
</itop_design>',
|
|
||||||
],
|
|
||||||
'merge non-existing leaf nodes without text have different behavior' => [
|
|
||||||
'sInitialXML' => '
|
|
||||||
<itop_design>
|
<itop_design>
|
||||||
</itop_design>',
|
|
||||||
'sDeltaXML' => '<itop_design>
|
|
||||||
<nodeA/>
|
<nodeA/>
|
||||||
</itop_design>',
|
</itop_design>',
|
||||||
'sExpectedXMLInLaxMode' => '<itop_design>
|
'sExpectedXMLInLaxMode' => '
|
||||||
<nodeA/>
|
<itop_design>
|
||||||
|
<nodeA/>
|
||||||
|
</itop_design>',
|
||||||
|
'sExpectedXMLInStrictMode' => '
|
||||||
|
<itop_design>
|
||||||
|
<nodeA/>
|
||||||
</itop_design>',
|
</itop_design>',
|
||||||
'sExpectedXMLInStrictMode' => null,
|
|
||||||
],
|
],
|
||||||
'merge non-existing nodes with sub-nodes defined' => [
|
|
||||||
|
'default no _delta on non-existing leaf nodes without text have different behavior' => [
|
||||||
'sInitialXML' => '
|
'sInitialXML' => '
|
||||||
<itop_design>
|
<itop_design>
|
||||||
</itop_design>',
|
</itop_design>',
|
||||||
'sDeltaXML' => '<itop_design>
|
'sDeltaXML' => '
|
||||||
|
<itop_design>
|
||||||
|
<nodeA/>
|
||||||
|
</itop_design>',
|
||||||
|
'sExpectedXMLInLaxMode' => '
|
||||||
|
<itop_design>
|
||||||
|
<nodeA/>
|
||||||
|
</itop_design>',
|
||||||
|
'sExpectedXMLInStrictMode' => '/itop_design/nodeA at line 3: could not be found or marked as removed (strict mode)',
|
||||||
|
],
|
||||||
|
|
||||||
|
'default no _delta on non-existing nodes with sub-nodes defined' => [
|
||||||
|
'sInitialXML' => '
|
||||||
|
<itop_design>
|
||||||
|
</itop_design>',
|
||||||
|
'sDeltaXML' => '
|
||||||
|
<itop_design>
|
||||||
<nodeA>
|
<nodeA>
|
||||||
<nodeB _delta="define"/>
|
<nodeB _delta="define"/>
|
||||||
</nodeA>
|
</nodeA>
|
||||||
</itop_design>',
|
</itop_design>',
|
||||||
'sExpectedXMLInLaxMode' => '<itop_design>
|
'sExpectedXMLInLaxMode' => '
|
||||||
|
<itop_design>
|
||||||
<nodeA>
|
<nodeA>
|
||||||
<nodeB _alteration="added"/>
|
<nodeB _alteration="added"/>
|
||||||
</nodeA>
|
</nodeA>
|
||||||
</itop_design>',
|
</itop_design>',
|
||||||
'sExpectedXMLInStrictMode' => '<itop_design>
|
'sExpectedXMLInStrictMode' => '
|
||||||
|
<itop_design>
|
||||||
<nodeA>
|
<nodeA>
|
||||||
<nodeB _alteration="added"/>
|
<nodeB _alteration="added"/>
|
||||||
</nodeA>
|
</nodeA>
|
||||||
|
</itop_design>',
|
||||||
|
],
|
||||||
|
|
||||||
|
'merge _delta on non-existing node must create node' => [
|
||||||
|
'sInitialXML' => '
|
||||||
|
<itop_design>
|
||||||
|
<nodeA>
|
||||||
|
<nodeB/>
|
||||||
|
</nodeA>
|
||||||
|
</itop_design>',
|
||||||
|
'sDeltaXML' => '
|
||||||
|
<itop_design load="strict">
|
||||||
|
<nodeA>
|
||||||
|
<nodeB>
|
||||||
|
<nodeC id="C_1" _delta="merge">
|
||||||
|
<items>
|
||||||
|
<item id="I_1" _delta="define">Test</item>
|
||||||
|
</items>
|
||||||
|
</nodeC>
|
||||||
|
</nodeB>
|
||||||
|
</nodeA>
|
||||||
|
</itop_design>',
|
||||||
|
'sExpectedXMLInLaxMode' => '
|
||||||
|
<itop_design>
|
||||||
|
<nodeA>
|
||||||
|
<nodeB>
|
||||||
|
<nodeC id="C_1" _alteration="added">
|
||||||
|
<items>
|
||||||
|
<item id="I_1">Test</item>
|
||||||
|
</items>
|
||||||
|
</nodeC>
|
||||||
|
</nodeB>
|
||||||
|
</nodeA>
|
||||||
|
</itop_design>',
|
||||||
|
'sExpectedXMLInStrictMode' => '
|
||||||
|
<itop_design>
|
||||||
|
<nodeA>
|
||||||
|
<nodeB>
|
||||||
|
<nodeC id="C_1" _alteration="added">
|
||||||
|
<items>
|
||||||
|
<item id="I_1">Test</item>
|
||||||
|
</items>
|
||||||
|
</nodeC>
|
||||||
|
</nodeB>
|
||||||
|
</nodeA>
|
||||||
|
</itop_design>',
|
||||||
|
],
|
||||||
|
|
||||||
|
'merge _delta on existing tree must merge...' => [
|
||||||
|
'sInitialXML' => '
|
||||||
|
<itop_design>
|
||||||
|
<nodeA>
|
||||||
|
<nodeB>
|
||||||
|
<nodeC id="C_1">
|
||||||
|
<items/>
|
||||||
|
</nodeC>
|
||||||
|
</nodeB>
|
||||||
|
</nodeA>
|
||||||
|
</itop_design>',
|
||||||
|
'sDeltaXML' => '
|
||||||
|
<itop_design load="strict">
|
||||||
|
<nodeA>
|
||||||
|
<nodeB>
|
||||||
|
<nodeC id="C_1" _delta="merge">
|
||||||
|
<items>
|
||||||
|
<item id="I_1" _delta="define">Test</item>
|
||||||
|
</items>
|
||||||
|
</nodeC>
|
||||||
|
</nodeB>
|
||||||
|
</nodeA>
|
||||||
|
</itop_design>',
|
||||||
|
'sExpectedXMLInLaxMode' => '
|
||||||
|
<itop_design>
|
||||||
|
<nodeA>
|
||||||
|
<nodeB>
|
||||||
|
<nodeC id="C_1">
|
||||||
|
<items>
|
||||||
|
<item id="I_1" _alteration="added">Test</item>
|
||||||
|
</items>
|
||||||
|
</nodeC>
|
||||||
|
</nodeB>
|
||||||
|
</nodeA>
|
||||||
|
</itop_design>',
|
||||||
|
'sExpectedXMLInStrictMode' => '
|
||||||
|
<itop_design>
|
||||||
|
<nodeA>
|
||||||
|
<nodeB>
|
||||||
|
<nodeC id="C_1">
|
||||||
|
<items>
|
||||||
|
<item id="I_1" _alteration="added">Test</item>
|
||||||
|
</items>
|
||||||
|
</nodeC>
|
||||||
|
</nodeB>
|
||||||
|
</nodeA>
|
||||||
</itop_design>',
|
</itop_design>',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user