VQMod offset issue in OpenCart - opencart

I`m trying to replace a chunk of code on the model with custom code, that I wrote.
Here is the code. I works, but it leaves a lot of offset.
Maybe there is a better way to do this
<operation info="Example of the vQmod">
<search position="replace" offset="3"><![CDATA[
Some code I want to Replace
Some code I want to Replace
Some code I want to Replace
]]></search>
<add><![CDATA[
Replaced Code
Replaced Code
Replaced Code
]]></add>
</operation>

Vqmods offset value is for replacing a line and the following x lines, however the search is for one line only. Vqmod doesn't match multiple lines in search.
Example :
Input
public function index() {
$a = rand();
$b = rand();
if ($a == $b) {
echo 'oh noes';
return false;
}
}
Script
<?xml version="1.0" encoding="UTF-8"?>
<modification>
<id>Replace many lines with one</id>
<version>1.0</version>
<vqmver>2.X</vqmver>
<author>xxx</author>
<file name="path/to/testfile.php">
<operation info="Replace index function">
<search position="replace" offset="7"><![CDATA[
public function index() {
]]></search>
<add><![CDATA[
public function index($arr = array()) {
foreach ($arr as $a) {
echo $a;
}
}
]]></add>
</operation>
</file>
</modification>
Output
public function index($arr = array()) {
foreach ($arr as $a) {
echo $a;
}
}
Note : There are still 7 blank lines. The offset clears the extra 7 lines of code from the input, but the replaced code is added in place of the initial line. So there will be 7 extra spaces after the new code, but it will not affect the code functionality, only the look of the vqcache file which is of no importance.

In Opencart, you cannot search for multiple lines of code and replace it with new multiple lines of codes. It can only search a single line and then replace or add with single line or multiple lines of code.
Offset is to search a single line of code and then offset the number of lines below and then replace or add new coding. Something like this:
<operation info="Example of the vQmod">
<search position="replace" offset="3"><![CDATA[
code I want to Replace at offset line 3
]]></search>
<add><![CDATA[
Replaced Code
add code
add code
]]></add>
</operation>

Related

REGEX Multi-line Search between 2 characters- Powershell

I am unable to apply many of the other powershell regex solutions to help solve my problem. The answer may very well already be on stackoverflow, but my lack of experience with powershell is prohibiting me from deducing how to maniupulate the solutions to my question.
I have a text file containing an XML document tree(I bring in the document tree as one large string into powershell)(edit 1) that includes the HTML tags to establish where certain content is. I need to steal the file name from in between the filename tags. Sometimes both tags and the file name are all on one line, and other times the tags are each on a seperate line as well as the file name. An example of the input data I have is below:
<files>
<file>
<fileName>
ThisTextFileINeedReturned.txt
</fileName>
<lastModifiedTime>1511883780000</lastModifiedTime>
<size>852192</size>
<isDirectory>false</isDirectory>
<isRegularFile>true</isRegularFile>
<isSymbolicLink>false</isSymbolicLink>
<isOther>false</isOther>
<group>group</group>
<transferStatus>Done</transferStatus>
</file>
<file>
<fileName>AnotherTextFileINeedReturned.txt</fileName>
<lastModifiedTime>1511883780000</lastModifiedTime>
<size>852192</size>
<isDirectory>false</isDirectory>
<isRegularFile>true</isRegularFile>
<isSymbolicLink>false</isSymbolicLink>
<isOther>false</isOther>
<group>group</group>
<transferStatus>Done</transferStatus>
</file>
I have created the following code to find the content within the tags thus far. It works if the filename tags and the file name are on the same line. The problem I'm having is in the instance where they are all on seperate lines (the example I provided above). I have already managed to transfer the large string above into $xmldata.
$xmldata -match '<fileName>(.*?)(</fileName>)'
$matches
Using the example text I displayed above, the output I receive is as follows:
<fileName>AnotherTextFileINeedReturned.txt</fileName>
I'm ok with receiving the tags, but I also need the name of the file that is on multiple lines. Like this...
<fileName>
ThisTextFileINeedReturned.txt
</fileName>
<fileName>AnotherTextFileINeedReturned.txt</fileName>
Or any variation that would give me both of the names of the text files. I have seen the (?m) part used before, but I haven't been able to successfully implement it. Thanks in advance for the help!! Let me know if you need any other information!
You should be able to get around that without using any regex. Powershell supports XML pretty well. Extracting the filename would be as easy as:
$Xml = #"
<files>
<file>
<fileName>
ThisTextFileINeedReturned.txt
</fileName>
<lastModifiedTime>1511883780000</lastModifiedTime>
<size>852192</size>
<isDirectory>false</isDirectory>
<isRegularFile>true</isRegularFile>
<isSymbolicLink>false</isSymbolicLink>
<isOther>false</isOther>
<group>group</group>
<transferStatus>Done</transferStatus>
</file>
<file>
<fileName>AnotherTextFileINeedReturned.txt</fileName>
<lastModifiedTime>1511883780000</lastModifiedTime>
<size>852192</size>
<isDirectory>false</isDirectory>
<isRegularFile>true</isRegularFile>
<isSymbolicLink>false</isSymbolicLink>
<isOther>false</isOther>
<group>group</group>
<transferStatus>Done</transferStatus>
</file>
</files>
"#
Select-Xml -Content $Xml -XPath "//files/file/fileName" | foreach {$_.node.InnerXML.Trim()}
You not explainen how you get your data but I guess you are using Get-Content to retrieve your source file. Get-Content reads the content one line at a time and returns a collection of objects, each of which represents a line of content. In other words, you're probably doing a Match on each separate line and therefor do no find the matches that are spread over multiple lines.
If this is indeed the case, the solution would be to simply join the lines first:
($xmldata -Join "") -match '<fileName>(.*?)(</fileName>)'
And check your matches, e.g.:
$Matches[0]

PowerShell string replacement

I am trying to build a PowerShell script such that I give it an input file and regex, it replaces the matching content with the environment variable.
For example,
If the input file contains the following:
<?xml version="1.0" encoding="utf-8"?>
<Application xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Name="fabric:/Services" xmlns="http://schemas.microsoft.com/2011/01/fabric">
<Parameters>
<Parameter Name="IntegrationManager_PartitionCount" Value="1" />
<Parameter Name="IntegrationManager_MinReplicaSetSize" Value="2" />
<Parameter Name="IntegrationManager_TargetReplicaSetSize" Value="#{INT_MGR_IC}" />
<Parameter Name="EventManager_InstanceCount" Value="#{EVT_MGR_IC}" />
<Parameter Name="Entities_InstanceCount" Value="#{ENT_IC}" />
<Parameter Name="Profile_InstanceCount" Value="#{PRF_IC}" />
<Parameter Name="Identity_InstanceCount" Value="#{IDNT_IC}" />
</Parameters>
</Application>
I would like to build a script that replaces #{INT_MGR_IC} with the value of the INT_MGR_IC environment variable and so on.
If you know of such script or can point me in the right direction, it would be a great help. Specifically, I am interested to know how to:
Extract and loop over keys from the file such as: #{INT_MGR_IC}, #{EVT_MGR_IC}, etc.
Once I have the key, how do I replace it with an associated environment variable. For example, #{INT_MGR_IC} with INT_MGR_IC env. variable.
Thanks a lot for looking into this :)
UPDATE 1
This is the RegEx I am planning to use: /#{(.+)}/g
Just load the file using the Get-Content cmdlet, iterate over each Parmeter, filter all parameter that Value starts with an #using Where-Object and change the value. Finally, use the Set-Content cmdlet to write it back:
$contentPath = 'Your_Path_Here'
$content = [xml] (Get-Content $contentPath)
$content.DocumentElement.Parameters.Parameter | Where Value -Match '^#' | ForEach-Object {
$_.Value = "REPLACE HERE"
}
$content | Set-Content $contentPath
In case you need to determine an environment variable, you could use [Environment]::GetEnvironmentVariable($_.Value).
Thanks a lot for everyone who helped. Especially, #jisaak :)
Here is the final script I built that solved the problem in the question. Hopefully its useful to someone!
$configPath = 'Cloud.xml'
$config = [xml] (Get-Content $configPath)
$config.DocumentElement.Parameters.Parameter | Where {$_.Value.StartsWith("#{")} | ForEach-Object {
$var = $_.Value.replace("#{","").replace("}","")
$val = (get-item env:$var).Value
Write-Host "Replacing $var with $val"
$_.Value = $val
}
$config.Save($configPath)

Why can't OCMod find lines of code?

I have an issue with OCMod, it randomly seems to not find lines of code, see below:
<file path="catalog/language/english/product/ymmproduct.php">
<operation>
<search trim="true"><![CDATA[
$_['tab_vehicle'] = 'Vehicles';
]]></search>
<add position="replace"><![CDATA[
$_['tab_vehicle'] = 'Bikes';
]]></add>
</operation>
</file>
the file path and ned is correct
i've tried the search with and without trimming [I'm guessing at what 'trim' does because it's not documented]
the line of code I'm searching for is absolutely there - I cut and pasted it from the target file then diff'd the contents.... NO DIFFERENCE.
I've tried it with and without line feeds in the CDATA
Nothing I have tried will find that line of code.
What could the issue be?
OCMod is not robust for a multiline search. If you can figure out how to do a single line search, it will be much more likely to work consistently. Since the file catalog/language/english/product/ymmproduct.php isn't in the default installation, is it yours? Perhaps you can create lines in it that will help guide OCMod so a single line search will work properly.

Get Image file name using regex wildcard search vqmod

I am wanting to remove the icons from the h1 title element in opencart admin panel. I'm trying to use an asterisk as a wildcard for the file name, but it's not working out.
The docs says the search data:
<h1><img src="view/image/*.png" alt="" /> <?php echo $heading_title; ?></h1>
should be a valid regex pattern, though I'm not familiar with regex. How can I do this correctly in vqmod?
<file name="admin/view/template/*/*.tpl">
<operation>
<search regex="true" position="replace"><![CDATA[
<h1><img src="view/image/*.png" alt="" /> <?php echo $heading_title; ?></h1>
]]></search>
<add><![CDATA[
<h1><?php echo $heading_title; ?></h1>
]]></add>
</operation>
</file>
In vQmod, the regex still needs to have its delimiters. You are also better off just using a generic search for the <h1> since you are setting it to just the heading title.
<file name="admin/view/template/*/*.tpl">
<operation>
<search regex="true" position="replace"><![CDATA[~<h1>.*?</h1>~]]></search>
<add><![CDATA[<h1><?php echo $heading_title; ?></h1>]]></add>
</operation>
</file>
In regex, an asterisk * is a quantifier which means match zero or more times.
I think you want to match anything, one or more times. You do that with .+. Ofcourse you want it ungreedy, so the final pattern is .+?.
. : match anything
+ : a quantifier which means match one or more times
? : + followed by ? means to match ungreedy
Let's apply the above in the code:
<h1><img src="view/image/.+?\.png" alt="" /> <?php echo preg_quote($heading_title); ?></h1>
We need to escape the dot in \.png
We'll use preg_quote() to escape properly regex reserved characters in the $heading_title variable

Multi line find (grapping) and replace text in XML file using perl

Here i am trying to find and replace text content in one XML file using perl regular expression.
Sample XML Code:
<root>
<add>
<st>xxxx</st>
<pin>xxx</pin>
</add>
</root>
Now i want to find / grep text from <add> to </add> and replace <xyz>xxx</xyz>
<add>
<st>xxxx</st>
<pin>xxx</pin>
</add>
Note:
if above content are in single line i mean without line break in between <add> to </add>, as <add><st>xxxx</st><pin>xxx</pin></add> i can use <add>(.*)<\/add> to find / grep.
Thanking You
Thirusanguraja V
Using XML::XSH2, a wrapper around XML::LibXML:
open input.xml ;
$add = /root/add ;
delete $add/* ;
insert element xyz into $add ;
insert text 'xxx' into $add/xyz ;
save :b ;