diff --git a/cumulusci/core/source_transforms/tests/test_transforms.py b/cumulusci/core/source_transforms/tests/test_transforms.py
index 99230f2fe2..4aa66204b2 100644
--- a/cumulusci/core/source_transforms/tests/test_transforms.py
+++ b/cumulusci/core/source_transforms/tests/test_transforms.py
@@ -883,6 +883,25 @@ def test_xpath_replace_with_exp_and_index(task_context):
zip_assert(builder, modified_zip_content)
+def test_xpath_replace_with_exp_and_index_has_xmlns(task_context):
+ zip_content = {
+ Path(
+ "Foo.xml"
+ ): ' Everyday Italian Giada De Laurentiis 2005 30.00 Harry Potter J K. Rowling 2005 29.99 XQuery Kick Start James McGovern Per Bothner Kurt Cagle James Linn Vaidyanathan Nagarajan 2003 49.99 Learning XML Erik T. Ray 2003 39.95 ',
+ }
+ patterns = [
+ {"xpath": "/bookstore/book[price>40]/author[2]", "replace": "Rich Author"}
+ ]
+ builder = create_builder(task_context, zip_content, patterns)
+
+ modified_zip_content = {
+ Path(
+ "Foo.xml"
+ ): ' Everyday Italian Giada De Laurentiis 2005 30.00 Harry Potter J K. Rowling 2005 29.99 XQuery Kick Start James McGovern Rich Author Kurt Cagle James Linn Vaidyanathan Nagarajan 2003 49.99 Learning XML Erik T. Ray 2003 39.95 ',
+ }
+ zip_assert(builder, modified_zip_content)
+
+
def test_xpath_replace_with_exp_and_index2(task_context):
zip_content = {
Path(
diff --git a/cumulusci/core/source_transforms/transforms.py b/cumulusci/core/source_transforms/transforms.py
index ab311b1456..d14ce196a7 100644
--- a/cumulusci/core/source_transforms/transforms.py
+++ b/cumulusci/core/source_transforms/transforms.py
@@ -2,7 +2,6 @@
import functools
import io
import os
-import re
import shutil
import typing as T
import zipfile
@@ -416,24 +415,6 @@ def __init__(self, options: FindReplaceTransformOptions):
self.options = options
def process(self, zf: ZipFile, context: TaskContext) -> ZipFile:
- # To handle xpath with namespaces, without
- def transform_xpath(expression):
- predicate_pattern = re.compile(r"\[.*?\]")
- parts = expression.split("/")
- transformed_parts = []
-
- for part in parts:
- if part:
- predicates = predicate_pattern.findall(part)
- tag = predicate_pattern.sub("", part)
- transformed_part = '/*[local-name()="' + tag + '"]'
- for predicate in predicates:
- transformed_part += predicate
- transformed_parts.append(transformed_part)
- transformed_expression = "".join(transformed_parts)
-
- return transformed_expression
-
def process_file(filename: str, content: str) -> T.Tuple[str, str]:
path = Path(filename)
for spec in self.options.patterns:
@@ -442,6 +423,7 @@ def process_file(filename: str, content: str) -> T.Tuple[str, str]:
):
try:
# See if the content is an xml file
+ content = content.replace(' xmlns="', ' xmlnamespace="')
content_bytes = content.encode("utf-8")
root = ET.fromstring(content_bytes)
@@ -460,8 +442,7 @@ def process_file(filename: str, content: str) -> T.Tuple[str, str]:
stack.extend(element)
# Modify the element given by xpath
elif spec.xpath:
- transformed_xpath = transform_xpath(spec.xpath)
- elements_to_replace = root.xpath(transformed_xpath)
+ elements_to_replace = root.xpath(spec.xpath)
for element in elements_to_replace:
element.text = spec.get_replace_string(context)
@@ -469,7 +450,7 @@ def process_file(filename: str, content: str) -> T.Tuple[str, str]:
content = ET.tostring(
root, encoding="utf-8", xml_declaration=has_xml_declaration
).decode("utf-8")
-
+ content = content.replace(' xmlnamespace="', ' xmlns="')
except ET.XMLSyntaxError:
if spec.find:
content = content.replace(