This is an automated email from the ASF dual-hosted git repository.
hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git
The following commit(s) were added to refs/heads/main by this push:
new b260832016 fix encoding on Get data from XML, fixes #5222 (#6938)
b260832016 is described below
commit b260832016686919144702136abc3cd52906b671
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Thu Apr 2 16:17:18 2026 +0200
fix encoding on Get data from XML, fixes #5222 (#6938)
---
.../transforms/xml/getxmldata/GetXmlData.java | 3 +-
.../getxmldata/LoopNodesImportProgressDialog.java | 3 +-
.../XmlInputFieldsImportProgressDialog.java | 3 +-
.../getxmldata/GetXmlDataWindows1252FileTest.java | 128 +++++++++++++++++++++
4 files changed, 134 insertions(+), 3 deletions(-)
diff --git
a/plugins/transforms/xml/src/main/java/org/apache/hop/pipeline/transforms/xml/getxmldata/GetXmlData.java
b/plugins/transforms/xml/src/main/java/org/apache/hop/pipeline/transforms/xml/getxmldata/GetXmlData.java
index b8f693df58..cb00941ea7 100644
---
a/plugins/transforms/xml/src/main/java/org/apache/hop/pipeline/transforms/xml/getxmldata/GetXmlData.java
+++
b/plugins/transforms/xml/src/main/java/org/apache/hop/pipeline/transforms/xml/getxmldata/GetXmlData.java
@@ -214,7 +214,8 @@ public class GetXmlData extends
BaseTransform<GetXmlDataMeta, GetXmlDataData> {
InputStream is = HopVfs.getInputStream(file);
CountingInputStream countingIs = new CountingInputStream(is);
try {
- data.document = reader.read(countingIs, encoding);
+ reader.setEncoding(encoding);
+ data.document = reader.read(countingIs);
dataVolumeIn = (dataVolumeIn != null ? dataVolumeIn : 0L) +
countingIs.getCount();
} finally {
BaseTransform.closeQuietly(countingIs);
diff --git
a/plugins/transforms/xml/src/main/java/org/apache/hop/pipeline/transforms/xml/getxmldata/LoopNodesImportProgressDialog.java
b/plugins/transforms/xml/src/main/java/org/apache/hop/pipeline/transforms/xml/getxmldata/LoopNodesImportProgressDialog.java
index 1313b9e965..1f5c00a76f 100644
---
a/plugins/transforms/xml/src/main/java/org/apache/hop/pipeline/transforms/xml/getxmldata/LoopNodesImportProgressDialog.java
+++
b/plugins/transforms/xml/src/main/java/org/apache/hop/pipeline/transforms/xml/getxmldata/LoopNodesImportProgressDialog.java
@@ -154,7 +154,8 @@ public class LoopNodesImportProgressDialog {
Document document = null;
if (!Utils.isEmpty(filename)) {
is = HopVfs.getInputStream(filename, variables);
- document = reader.read(is, encoding);
+ reader.setEncoding(encoding);
+ document = reader.read(is);
} else {
if (!Utils.isEmpty(xml)) {
document = reader.read(new StringReader(xml));
diff --git
a/plugins/transforms/xml/src/main/java/org/apache/hop/pipeline/transforms/xml/getxmldata/XmlInputFieldsImportProgressDialog.java
b/plugins/transforms/xml/src/main/java/org/apache/hop/pipeline/transforms/xml/getxmldata/XmlInputFieldsImportProgressDialog.java
index 7edca73ba9..7b761e27a6 100644
---
a/plugins/transforms/xml/src/main/java/org/apache/hop/pipeline/transforms/xml/getxmldata/XmlInputFieldsImportProgressDialog.java
+++
b/plugins/transforms/xml/src/main/java/org/apache/hop/pipeline/transforms/xml/getxmldata/XmlInputFieldsImportProgressDialog.java
@@ -175,7 +175,8 @@ public class XmlInputFieldsImportProgressDialog {
Document document = null;
if (!Utils.isEmpty(filename)) {
is = HopVfs.getInputStream(filename, variables);
- document = reader.read(is, encoding);
+ reader.setEncoding(encoding);
+ document = reader.read(is);
} else {
if (!Utils.isEmpty(xml)) {
document = reader.read(new StringReader(xml));
diff --git
a/plugins/transforms/xml/src/test/java/org/apache/hop/pipeline/transforms/xml/getxmldata/GetXmlDataWindows1252FileTest.java
b/plugins/transforms/xml/src/test/java/org/apache/hop/pipeline/transforms/xml/getxmldata/GetXmlDataWindows1252FileTest.java
new file mode 100644
index 0000000000..b35e9c31a3
--- /dev/null
+++
b/plugins/transforms/xml/src/test/java/org/apache/hop/pipeline/transforms/xml/getxmldata/GetXmlDataWindows1252FileTest.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.pipeline.transforms.xml.getxmldata;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
+
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import org.apache.hop.core.HopEnvironment;
+import org.apache.hop.core.RowMetaAndData;
+import org.apache.hop.core.plugins.PluginRegistry;
+import org.apache.hop.core.plugins.TransformPluginType;
+import org.apache.hop.core.row.IValueMeta;
+import org.apache.hop.core.row.value.ValueMetaFactory;
+import org.apache.hop.junit.rules.RestoreHopEnvironmentExtension;
+import org.apache.hop.pipeline.Pipeline;
+import org.apache.hop.pipeline.PipelineHopMeta;
+import org.apache.hop.pipeline.PipelineMeta;
+import org.apache.hop.pipeline.engines.local.LocalPipelineEngine;
+import org.apache.hop.pipeline.transform.ITransform;
+import org.apache.hop.pipeline.transform.TransformMeta;
+import org.apache.hop.pipeline.transforms.dummy.DummyMeta;
+import org.apache.hop.pipeline.transforms.xml.RowTransformCollector;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.io.TempDir;
+
+/**
+ * Ensures file-based parsing honors the transform encoding when the XML
declaration omits
+ * encoding="..." (SAX must use {@link org.dom4j.io.SAXReader#setEncoding},
not read(InputStream,
+ * String) which treats the second argument as systemId).
+ */
+@ExtendWith(RestoreHopEnvironmentExtension.class)
+class GetXmlDataWindows1252FileTest {
+
+ @TempDir Path tempDir;
+
+ @BeforeEach
+ void init() throws Exception {
+ HopEnvironment.init();
+ }
+
+ @Test
+ void testWindows1252FileWithoutEncodingInDeclaration() throws Exception {
+ assumeTrue(Charset.isSupported("Windows-1252"));
+
+ Charset cp1252 = Charset.forName("Windows-1252");
+ // Prolog without encoding: parser must use transform encoding
(Windows-1252).
+ // U+00E9 is single byte 0xE9 in cp1252; UTF-8 would be 0xC3 0xA9 and
breaks if misread.
+ String logicalXml = "<?xml
version=\"1.0\"?>\n<root><row><name>caf\u00e9</name></row></root>\n";
+ Path xmlFile = tempDir.resolve("cp1252-sample.xml");
+ Files.write(xmlFile, logicalXml.getBytes(cp1252));
+
+ String fileUri = xmlFile.toAbsolutePath().toUri().toString();
+
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("getxmldata-cp1252-file");
+
+ PluginRegistry registry = PluginRegistry.getInstance();
+
+ GetXmlDataMeta gxdm = new GetXmlDataMeta();
+ gxdm.setInFields(false);
+ gxdm.setAFile(false);
+ gxdm.setReadUrl(false);
+ gxdm.setEncoding("Windows-1252");
+ gxdm.setLoopXPath("root/row");
+ gxdm.setDoNotFailIfNoFile(false);
+ gxdm.setFilesList(
+ List.of(new GetXmlFileItem(fileUri, "", "",
GetXmlDataMeta.RequiredFilesCode[1], "N")));
+
+ GetXmlDataField nameField = new GetXmlDataField("name_out");
+ nameField.setXPath("name");
+
nameField.setElementType(GetXmlDataField.getElementTypeCode(GetXmlDataField.ELEMENT_TYPE_NODE));
+
nameField.setType(ValueMetaFactory.getValueMetaName(IValueMeta.TYPE_STRING));
+ nameField.setFormat("");
+ nameField.setLength(-1);
+ nameField.setPrecision(-1);
+ nameField.setCurrencySymbol("");
+ nameField.setDecimalSymbol("");
+ nameField.setGroupSymbol("");
+
nameField.setTrimType(GetXmlDataField.getTrimTypeCode(GetXmlDataField.TYPE_TRIM_NONE));
+ gxdm.setInputFields(List.of(nameField));
+
+ String getXmlPid = registry.getPluginId(TransformPluginType.class, gxdm);
+ TransformMeta getXmlTransform = new TransformMeta(getXmlPid, "get xml
data", gxdm);
+ pipelineMeta.addTransform(getXmlTransform);
+
+ DummyMeta dm = new DummyMeta();
+ String dummyPid = registry.getPluginId(TransformPluginType.class, dm);
+ TransformMeta dummyTransform = new TransformMeta(dummyPid, "dummy", dm);
+ pipelineMeta.addTransform(dummyTransform);
+
+ pipelineMeta.addPipelineHop(new PipelineHopMeta(getXmlTransform,
dummyTransform));
+
+ Pipeline pipeline = new LocalPipelineEngine(pipelineMeta);
+ pipeline.prepareExecution();
+
+ ITransform dummyStep = pipeline.getTransform("dummy", 0);
+ RowTransformCollector collector = new RowTransformCollector();
+ dummyStep.addRowListener(collector);
+
+ pipeline.startThreads();
+ pipeline.waitUntilFinished();
+
+ List<RowMetaAndData> rows = collector.getRowsWritten();
+ assertEquals(1, rows.size(), "Expected one row from one <row> element");
+ assertEquals("caf\u00e9", rows.get(0).getString("name_out", ""));
+ }
+}