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 5fc8057c7f Improve YAML Input with nested JsonPath expressions (#7432)
5fc8057c7f is described below

commit 5fc8057c7f84a19e8d421bf5fb677875dcbd5e20
Author: Lance <[email protected]>
AuthorDate: Thu Jul 9 18:43:17 2026 +0800

    Improve YAML Input with nested JsonPath expressions (#7432)
    
    * Improve YAML Input with nested JsonPath expressions
    
    Signed-off-by: lance <[email protected]>
    
    * Improve YAML Input with nested JsonPath expressions
    
    Signed-off-by: lance <[email protected]>
    
    * add license
    
    Signed-off-by: lance <[email protected]>
    
    * add some tests
    
    ---------
    
    Signed-off-by: lance <[email protected]>
    Co-authored-by: Hans Van Akelyen <[email protected]>
---
 ...nput-validate.hpl => 0088-yaml-input-field.hpl} | 170 +++++++------
 ...input-validate.hpl => 0088-yaml-input-list.hpl} |  88 +------
 ...alidate.hpl => 0088-yaml-input-multi-level.hpl} | 167 +++++-------
 ...t-validate.hpl => 0088-yaml-input-multidoc.hpl} |  72 +-----
 .../transforms/0088-yaml-input-validate.hpl        | 139 +++++-----
 .../datasets/golden-yaml-input-field.csv           |   3 +
 .../transforms/datasets/golden-yaml-input-list.csv |   6 +
 .../datasets/golden-yaml-input-multi-level.csv     |   6 +
 .../datasets/golden-yaml-input-multidoc.csv        |   4 +
 .../transforms/datasets/golden-yaml-input.csv      |   6 +-
 .../transforms/files/yaml-input-list.yaml          |  25 ++
 .../transforms/files/yaml-input-multi-level.yaml   |  35 +++
 .../transforms/files/yaml-input-multidoc.yaml      |  31 +++
 ...088-yaml-input.hwf => main-0088-yaml-input.hwf} |  11 +-
 .../metadata/dataset/golden-yaml-input-field.json  |  32 +++
 .../metadata/dataset/golden-yaml-input-list.json   |  16 ++
 .../dataset/golden-yaml-input-multi-level.json     |  32 +++
 .../dataset/golden-yaml-input-multidoc.json        |  32 +++
 .../0088-yaml-input-field-validate UNIT.json       |  38 +++
 .../0088-yaml-input-list-validate UNIT.json        |  28 +++
 .../0088-yaml-input-multi-level UNIT.json          |  38 +++
 .../0088-yaml-input-multidoc-validate UNIT.json    |  38 +++
 plugins/transforms/yamlinput/pom.xml               |   6 +
 .../pipeline/transforms/yamlinput/YamlInput.java   |  17 +-
 .../transforms/yamlinput/YamlInputData.java        |   4 +
 .../transforms/yamlinput/YamlInputDialog.java      |   6 +-
 .../transforms/yamlinput/YamlPathResolver.java     |  64 +++++
 .../pipeline/transforms/yamlinput/YamlReader.java  | 280 ++++++++++++++++++---
 .../yamlinput/messages/messages_en_US.properties   |   6 +-
 .../transforms/yamlinput/YamlInputTests.java       |   3 +
 .../yamlinput/YamlPathResolverTests.java           |  71 ++++++
 .../transforms/yamlinput/YamlReaderTests.java      | 166 +++++++++++-
 32 files changed, 1189 insertions(+), 451 deletions(-)

diff --git a/integration-tests/transforms/0088-yaml-input-validate.hpl 
b/integration-tests/transforms/0088-yaml-input-field.hpl
similarity index 64%
copy from integration-tests/transforms/0088-yaml-input-validate.hpl
copy to integration-tests/transforms/0088-yaml-input-field.hpl
index 1c70c26701..493bc72040 100644
--- a/integration-tests/transforms/0088-yaml-input-validate.hpl
+++ b/integration-tests/transforms/0088-yaml-input-field.hpl
@@ -19,7 +19,7 @@ limitations under the License.
 -->
 <pipeline>
   <info>
-    <name>0088-yaml-input-validate</name>
+    <name>0088-yaml-input-field</name>
     <name_sync_with_filename>Y</name_sync_with_filename>
     <description/>
     <extended_description/>
@@ -31,22 +31,32 @@ limitations under the License.
     
<transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
     
<transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
     <created_user>-</created_user>
-    <created_date>2026/03/24 20:36:32.371</created_date>
+    <created_date>2026/07/09 11:00:00.000</created_date>
     <modified_user>-</modified_user>
-    <modified_date>2026/03/24 20:36:32.371</modified_date>
+    <modified_date>2026/07/09 11:00:00.000</modified_date>
   </info>
   <notepads>
   </notepads>
   <order>
     <hop>
-      <from>files/yaml-input.yaml</from>
+      <from>generate yaml rows</from>
+      <to>parse yaml field</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>parse yaml field</from>
+      <to>keep extracted fields</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>keep extracted fields</from>
       <to>validate</to>
       <enabled>Y</enabled>
     </hop>
   </order>
   <transform>
-    <name>files/yaml-input.yaml</name>
-    <type>YamlInput</type>
+    <name>generate yaml rows</name>
+    <type>DataGrid</type>
     <description/>
     <distribute>Y</distribute>
     <custom_distribution/>
@@ -55,37 +65,20 @@ limitations under the License.
       <method>none</method>
       <schema_name/>
     </partitioning>
-    <include>N</include>
-    <include_field/>
-    <rownum>N</rownum>
-    <addresultfile>N</addresultfile>
-    <validating>N</validating>
-    <IsIgnoreEmptyFile>N</IsIgnoreEmptyFile>
-    <doNotFailIfNoFile>Y</doNotFailIfNoFile>
-    <rownum_field/>
-    <encoding/>
-    <file>
-      <name>${PROJECT_HOME}/files/yaml-input.yaml</name>
-      <filemask/>
-      <file_required>N</file_required>
-      <include_subfolders>N</include_subfolders>
-    </file>
     <fields>
       <field>
-        <name>organisation</name>
-        <path>organisation</path>
-        <type>String</type>
+        <name>id</name>
+        <type>Integer</type>
         <format/>
         <currency/>
         <decimal/>
         <group/>
         <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
+        <precision>0</precision>
+        <set_empty_string>N</set_empty_string>
       </field>
       <field>
-        <name>acronym</name>
-        <path>acronym</path>
+        <name>yaml</name>
         <type>String</type>
         <format/>
         <currency/>
@@ -93,11 +86,54 @@ limitations under the License.
         <group/>
         <length>-1</length>
         <precision>-1</precision>
-        <trim_type>none</trim_type>
+        <set_empty_string>N</set_empty_string>
       </field>
+    </fields>
+    <data>
+      <line>
+        <item>1</item>
+        <item>{name: Spark, version: "4.0.0"}</item>
+      </line>
+      <line>
+        <item>2</item>
+        <item>{name: Flink, version: "1.20"}</item>
+      </line>
+    </data>
+    <GUI>
+      <xloc>80</xloc>
+      <yloc>64</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>parse yaml field</name>
+    <type>YamlInput</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <include>N</include>
+    <include_field/>
+    <rownum>N</rownum>
+    <addresultfile>N</addresultfile>
+    <validating>N</validating>
+    <IsIgnoreEmptyFile>N</IsIgnoreEmptyFile>
+    <doNotFailIfNoFile>Y</doNotFailIfNoFile>
+    <rownum_field/>
+    <encoding/>
+    <file>
+      <name/>
+      <filemask/>
+      <file_required>N</file_required>
+      <include_subfolders>N</include_subfolders>
+    </file>
+    <fields>
       <field>
-        <name>project</name>
-        <path>project</path>
+        <name>name</name>
+        <path>name</path>
         <type>String</type>
         <format/>
         <currency/>
@@ -108,9 +144,9 @@ limitations under the License.
         <trim_type>none</trim_type>
       </field>
       <field>
-        <name>javaFileCount</name>
-        <path>javaFileCount</path>
-        <type>Integer</type>
+        <name>version</name>
+        <path>version</path>
+        <type>String</type>
         <format/>
         <currency/>
         <decimal/>
@@ -119,50 +155,42 @@ limitations under the License.
         <precision>-1</precision>
         <trim_type>none</trim_type>
       </field>
+    </fields>
+    <limit>0</limit>
+    <IsInFields>Y</IsInFields>
+    <IsAFile>N</IsAFile>
+    <YamlField>yaml</YamlField>
+    <attributes/>
+    <GUI>
+      <xloc>272</xloc>
+      <yloc>64</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>keep extracted fields</name>
+    <type>SelectValues</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <fields>
       <field>
-        <name>awesome</name>
-        <path>awesome</path>
-        <type>Boolean</type>
-        <format/>
-        <currency/>
-        <decimal/>
-        <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
+        <name>id</name>
       </field>
       <field>
-        <name>used-apache-projects</name>
-        <path>used-apache-projects</path>
-        <type>String</type>
-        <format/>
-        <currency/>
-        <decimal/>
-        <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
+        <name>name</name>
       </field>
       <field>
-        <name>statistics</name>
-        <path>statistics</path>
-        <type>String</type>
-        <format/>
-        <currency/>
-        <decimal/>
-        <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
+        <name>version</name>
       </field>
+      <select_unspecified>N</select_unspecified>
     </fields>
-    <limit>0</limit>
-    <IsInFields>N</IsInFields>
-    <IsAFile>N</IsAFile>
-    <YamlField/>
-    <attributes/>
     <GUI>
-      <xloc>80</xloc>
+      <xloc>464</xloc>
       <yloc>64</yloc>
     </GUI>
   </transform>
@@ -179,7 +207,7 @@ limitations under the License.
     </partitioning>
     <attributes/>
     <GUI>
-      <xloc>288</xloc>
+      <xloc>656</xloc>
       <yloc>64</yloc>
     </GUI>
   </transform>
diff --git a/integration-tests/transforms/0088-yaml-input-validate.hpl 
b/integration-tests/transforms/0088-yaml-input-list.hpl
similarity index 58%
copy from integration-tests/transforms/0088-yaml-input-validate.hpl
copy to integration-tests/transforms/0088-yaml-input-list.hpl
index 1c70c26701..a3c4c4b2d7 100644
--- a/integration-tests/transforms/0088-yaml-input-validate.hpl
+++ b/integration-tests/transforms/0088-yaml-input-list.hpl
@@ -19,7 +19,7 @@ limitations under the License.
 -->
 <pipeline>
   <info>
-    <name>0088-yaml-input-validate</name>
+    <name>0088-yaml-input-list</name>
     <name_sync_with_filename>Y</name_sync_with_filename>
     <description/>
     <extended_description/>
@@ -31,21 +31,21 @@ limitations under the License.
     
<transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
     
<transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
     <created_user>-</created_user>
-    <created_date>2026/03/24 20:36:32.371</created_date>
+    <created_date>2026/07/09 11:00:00.000</created_date>
     <modified_user>-</modified_user>
-    <modified_date>2026/03/24 20:36:32.371</modified_date>
+    <modified_date>2026/07/09 11:00:00.000</modified_date>
   </info>
   <notepads>
   </notepads>
   <order>
     <hop>
-      <from>files/yaml-input.yaml</from>
+      <from>files/yaml-input-list.yaml</from>
       <to>validate</to>
       <enabled>Y</enabled>
     </hop>
   </order>
   <transform>
-    <name>files/yaml-input.yaml</name>
+    <name>files/yaml-input-list.yaml</name>
     <type>YamlInput</type>
     <description/>
     <distribute>Y</distribute>
@@ -65,87 +65,15 @@ limitations under the License.
     <rownum_field/>
     <encoding/>
     <file>
-      <name>${PROJECT_HOME}/files/yaml-input.yaml</name>
+      <name>${PROJECT_HOME}/files/yaml-input-list.yaml</name>
       <filemask/>
       <file_required>N</file_required>
       <include_subfolders>N</include_subfolders>
     </file>
     <fields>
       <field>
-        <name>organisation</name>
-        <path>organisation</path>
-        <type>String</type>
-        <format/>
-        <currency/>
-        <decimal/>
-        <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
-      </field>
-      <field>
-        <name>acronym</name>
-        <path>acronym</path>
-        <type>String</type>
-        <format/>
-        <currency/>
-        <decimal/>
-        <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
-      </field>
-      <field>
-        <name>project</name>
-        <path>project</path>
-        <type>String</type>
-        <format/>
-        <currency/>
-        <decimal/>
-        <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
-      </field>
-      <field>
-        <name>javaFileCount</name>
-        <path>javaFileCount</path>
-        <type>Integer</type>
-        <format/>
-        <currency/>
-        <decimal/>
-        <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
-      </field>
-      <field>
-        <name>awesome</name>
-        <path>awesome</path>
-        <type>Boolean</type>
-        <format/>
-        <currency/>
-        <decimal/>
-        <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
-      </field>
-      <field>
-        <name>used-apache-projects</name>
-        <path>used-apache-projects</path>
-        <type>String</type>
-        <format/>
-        <currency/>
-        <decimal/>
-        <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
-      </field>
-      <field>
-        <name>statistics</name>
-        <path>statistics</path>
+        <name>engine</name>
+        <path>engine</path>
         <type>String</type>
         <format/>
         <currency/>
diff --git a/integration-tests/transforms/0088-yaml-input-validate.hpl 
b/integration-tests/transforms/0088-yaml-input-multi-level.hpl
similarity index 58%
copy from integration-tests/transforms/0088-yaml-input-validate.hpl
copy to integration-tests/transforms/0088-yaml-input-multi-level.hpl
index 1c70c26701..73351ccfd1 100644
--- a/integration-tests/transforms/0088-yaml-input-validate.hpl
+++ b/integration-tests/transforms/0088-yaml-input-multi-level.hpl
@@ -19,171 +19,116 @@ limitations under the License.
 -->
 <pipeline>
   <info>
-    <name>0088-yaml-input-validate</name>
-    <name_sync_with_filename>Y</name_sync_with_filename>
-    <description/>
-    <extended_description/>
-    <pipeline_version/>
-    <pipeline_type>Normal</pipeline_type>
-    <parameters>
-    </parameters>
     <capture_transform_performance>N</capture_transform_performance>
     
<transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
     
<transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <pipeline_type>Normal</pipeline_type>
+    <pipeline_status>-1</pipeline_status>
+    <parameters/>
+    <name>New pipeline</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
     <created_user>-</created_user>
-    <created_date>2026/03/24 20:36:32.371</created_date>
     <modified_user>-</modified_user>
-    <modified_date>2026/03/24 20:36:32.371</modified_date>
+    <created_date>2026/07/05 10:23:55.458</created_date>
+    <modified_date>2026/07/05 10:23:55.458</modified_date>
   </info>
-  <notepads>
-  </notepads>
-  <order>
-    <hop>
-      <from>files/yaml-input.yaml</from>
-      <to>validate</to>
-      <enabled>Y</enabled>
-    </hop>
-  </order>
   <transform>
-    <name>files/yaml-input.yaml</name>
     <type>YamlInput</type>
-    <description/>
-    <distribute>Y</distribute>
-    <custom_distribution/>
-    <copies>1</copies>
-    <partitioning>
-      <method>none</method>
-      <schema_name/>
-    </partitioning>
+    <name>files/yaml-input.yaml</name>
     <include>N</include>
     <include_field/>
     <rownum>N</rownum>
+    <rownum_field/>
+    <limit>0</limit>
+    <encoding/>
+    <YamlField/>
+    <IsInFields>N</IsInFields>
+    <IsAFile>N</IsAFile>
     <addresultfile>N</addresultfile>
     <validating>N</validating>
     <IsIgnoreEmptyFile>N</IsIgnoreEmptyFile>
     <doNotFailIfNoFile>Y</doNotFailIfNoFile>
-    <rownum_field/>
-    <encoding/>
-    <file>
-      <name>${PROJECT_HOME}/files/yaml-input.yaml</name>
-      <filemask/>
-      <file_required>N</file_required>
-      <include_subfolders>N</include_subfolders>
-    </file>
+    <files>
+      <file>
+        <name>${PROJECT_HOME}/files/yaml-input-multi-level.yaml</name>
+        <filemask/>
+        <file_required>N</file_required>
+        <include_subfolders>N</include_subfolders>
+      </file>
+    </files>
     <fields>
       <field>
-        <name>organisation</name>
-        <path>organisation</path>
+        <name>tableName</name>
+        <path>$.tables[*].tableName</path>
         <type>String</type>
-        <format/>
-        <currency/>
-        <decimal/>
-        <group/>
         <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
-      </field>
-      <field>
-        <name>acronym</name>
-        <path>acronym</path>
-        <type>String</type>
         <format/>
-        <currency/>
-        <decimal/>
-        <group/>
-        <length>-1</length>
-        <precision>-1</precision>
         <trim_type>none</trim_type>
-      </field>
-      <field>
-        <name>project</name>
-        <path>project</path>
-        <type>String</type>
-        <format/>
+        <precision>-1</precision>
         <currency/>
         <decimal/>
         <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
       </field>
       <field>
-        <name>javaFileCount</name>
-        <path>javaFileCount</path>
+        <name>dataPagination</name>
+        <path>$.tables[*].dataPagination</path>
         <type>Integer</type>
-        <format/>
-        <currency/>
-        <decimal/>
-        <group/>
         <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
-      </field>
-      <field>
-        <name>awesome</name>
-        <path>awesome</path>
-        <type>Boolean</type>
         <format/>
-        <currency/>
-        <decimal/>
-        <group/>
-        <length>-1</length>
-        <precision>-1</precision>
         <trim_type>none</trim_type>
-      </field>
-      <field>
-        <name>used-apache-projects</name>
-        <path>used-apache-projects</path>
-        <type>String</type>
-        <format/>
+        <precision>-1</precision>
         <currency/>
         <decimal/>
         <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
       </field>
       <field>
-        <name>statistics</name>
-        <path>statistics</path>
+        <name>queryDataset</name>
+        <path>$.tables[*].queryDataset</path>
         <type>String</type>
+        <length>-1</length>
         <format/>
+        <trim_type>none</trim_type>
+        <precision>-1</precision>
         <currency/>
         <decimal/>
         <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
       </field>
     </fields>
-    <limit>0</limit>
-    <IsInFields>N</IsInFields>
-    <IsAFile>N</IsAFile>
-    <YamlField/>
-    <attributes/>
+    <distribute>N</distribute>
+    <copies>1</copies>
     <GUI>
-      <xloc>80</xloc>
-      <yloc>64</yloc>
+      <xloc>96</xloc>
+      <yloc>48</yloc>
     </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
   </transform>
   <transform>
-    <name>validate</name>
     <type>Dummy</type>
-    <description/>
+    <name>validate</name>
     <distribute>Y</distribute>
-    <custom_distribution/>
     <copies>1</copies>
+    <GUI>
+      <xloc>320</xloc>
+      <yloc>48</yloc>
+    </GUI>
     <partitioning>
       <method>none</method>
       <schema_name/>
     </partitioning>
     <attributes/>
-    <GUI>
-      <xloc>288</xloc>
-      <yloc>64</yloc>
-    </GUI>
   </transform>
-  <transform_error_handling>
-  </transform_error_handling>
+  <order>
+    <hop>
+      <from>files/yaml-input.yaml</from>
+      <to>validate</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <notepads/>
   <attributes/>
+  <transform_error_handling/>
 </pipeline>
diff --git a/integration-tests/transforms/0088-yaml-input-validate.hpl 
b/integration-tests/transforms/0088-yaml-input-multidoc.hpl
similarity index 67%
copy from integration-tests/transforms/0088-yaml-input-validate.hpl
copy to integration-tests/transforms/0088-yaml-input-multidoc.hpl
index 1c70c26701..ee18141400 100644
--- a/integration-tests/transforms/0088-yaml-input-validate.hpl
+++ b/integration-tests/transforms/0088-yaml-input-multidoc.hpl
@@ -19,7 +19,7 @@ limitations under the License.
 -->
 <pipeline>
   <info>
-    <name>0088-yaml-input-validate</name>
+    <name>0088-yaml-input-multidoc</name>
     <name_sync_with_filename>Y</name_sync_with_filename>
     <description/>
     <extended_description/>
@@ -31,21 +31,21 @@ limitations under the License.
     
<transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
     
<transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
     <created_user>-</created_user>
-    <created_date>2026/03/24 20:36:32.371</created_date>
+    <created_date>2026/07/09 11:00:00.000</created_date>
     <modified_user>-</modified_user>
-    <modified_date>2026/03/24 20:36:32.371</modified_date>
+    <modified_date>2026/07/09 11:00:00.000</modified_date>
   </info>
   <notepads>
   </notepads>
   <order>
     <hop>
-      <from>files/yaml-input.yaml</from>
+      <from>files/yaml-input-multidoc.yaml</from>
       <to>validate</to>
       <enabled>Y</enabled>
     </hop>
   </order>
   <transform>
-    <name>files/yaml-input.yaml</name>
+    <name>files/yaml-input-multidoc.yaml</name>
     <type>YamlInput</type>
     <description/>
     <distribute>Y</distribute>
@@ -65,15 +65,15 @@ limitations under the License.
     <rownum_field/>
     <encoding/>
     <file>
-      <name>${PROJECT_HOME}/files/yaml-input.yaml</name>
+      <name>${PROJECT_HOME}/files/yaml-input-multidoc.yaml</name>
       <filemask/>
       <file_required>N</file_required>
       <include_subfolders>N</include_subfolders>
     </file>
     <fields>
       <field>
-        <name>organisation</name>
-        <path>organisation</path>
+        <name>name</name>
+        <path>name</path>
         <type>String</type>
         <format/>
         <currency/>
@@ -84,8 +84,8 @@ limitations under the License.
         <trim_type>none</trim_type>
       </field>
       <field>
-        <name>acronym</name>
-        <path>acronym</path>
+        <name>type</name>
+        <path>type</path>
         <type>String</type>
         <format/>
         <currency/>
@@ -96,32 +96,8 @@ limitations under the License.
         <trim_type>none</trim_type>
       </field>
       <field>
-        <name>project</name>
-        <path>project</path>
-        <type>String</type>
-        <format/>
-        <currency/>
-        <decimal/>
-        <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
-      </field>
-      <field>
-        <name>javaFileCount</name>
-        <path>javaFileCount</path>
-        <type>Integer</type>
-        <format/>
-        <currency/>
-        <decimal/>
-        <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
-      </field>
-      <field>
-        <name>awesome</name>
-        <path>awesome</path>
+        <name>distributed</name>
+        <path>distributed</path>
         <type>Boolean</type>
         <format/>
         <currency/>
@@ -131,30 +107,6 @@ limitations under the License.
         <precision>-1</precision>
         <trim_type>none</trim_type>
       </field>
-      <field>
-        <name>used-apache-projects</name>
-        <path>used-apache-projects</path>
-        <type>String</type>
-        <format/>
-        <currency/>
-        <decimal/>
-        <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
-      </field>
-      <field>
-        <name>statistics</name>
-        <path>statistics</path>
-        <type>String</type>
-        <format/>
-        <currency/>
-        <decimal/>
-        <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
-      </field>
     </fields>
     <limit>0</limit>
     <IsInFields>N</IsInFields>
diff --git a/integration-tests/transforms/0088-yaml-input-validate.hpl 
b/integration-tests/transforms/0088-yaml-input-validate.hpl
index 1c70c26701..8ccc00fff5 100644
--- a/integration-tests/transforms/0088-yaml-input-validate.hpl
+++ b/integration-tests/transforms/0088-yaml-input-validate.hpl
@@ -19,171 +19,168 @@ limitations under the License.
 -->
 <pipeline>
   <info>
-    <name>0088-yaml-input-validate</name>
-    <name_sync_with_filename>Y</name_sync_with_filename>
-    <description/>
-    <extended_description/>
     <pipeline_version/>
-    <pipeline_type>Normal</pipeline_type>
-    <parameters>
-    </parameters>
     <capture_transform_performance>N</capture_transform_performance>
     
<transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
     
<transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <pipeline_type>Normal</pipeline_type>
+    <pipeline_status>0</pipeline_status>
+    <parameters/>
+    <name>0088-yaml-input-validate</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description/>
+    <extended_description/>
     <created_user>-</created_user>
-    <created_date>2026/03/24 20:36:32.371</created_date>
     <modified_user>-</modified_user>
+    <created_date>2026/03/24 20:36:32.371</created_date>
     <modified_date>2026/03/24 20:36:32.371</modified_date>
   </info>
-  <notepads>
-  </notepads>
-  <order>
-    <hop>
-      <from>files/yaml-input.yaml</from>
-      <to>validate</to>
-      <enabled>Y</enabled>
-    </hop>
-  </order>
   <transform>
-    <name>files/yaml-input.yaml</name>
     <type>YamlInput</type>
-    <description/>
-    <distribute>Y</distribute>
-    <custom_distribution/>
-    <copies>1</copies>
-    <partitioning>
-      <method>none</method>
-      <schema_name/>
-    </partitioning>
+    <name>files/yaml-input.yaml</name>
     <include>N</include>
     <include_field/>
     <rownum>N</rownum>
+    <rownum_field/>
+    <limit>0</limit>
+    <encoding/>
+    <YamlField/>
+    <IsInFields>N</IsInFields>
+    <IsAFile>N</IsAFile>
     <addresultfile>N</addresultfile>
     <validating>N</validating>
     <IsIgnoreEmptyFile>N</IsIgnoreEmptyFile>
     <doNotFailIfNoFile>Y</doNotFailIfNoFile>
-    <rownum_field/>
-    <encoding/>
-    <file>
-      <name>${PROJECT_HOME}/files/yaml-input.yaml</name>
-      <filemask/>
-      <file_required>N</file_required>
-      <include_subfolders>N</include_subfolders>
-    </file>
+    <files>
+      <file>
+        <name>${PROJECT_HOME}/files/yaml-input.yaml</name>
+        <file_required>N</file_required>
+        <include_subfolders>N</include_subfolders>
+      </file>
+    </files>
     <fields>
       <field>
         <name>organisation</name>
         <path>organisation</path>
         <type>String</type>
+        <length>-1</length>
         <format/>
+        <trim_type>none</trim_type>
+        <precision>-1</precision>
         <currency/>
         <decimal/>
         <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
       </field>
       <field>
         <name>acronym</name>
         <path>acronym</path>
         <type>String</type>
+        <length>-1</length>
         <format/>
+        <trim_type>none</trim_type>
+        <precision>-1</precision>
         <currency/>
         <decimal/>
         <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
       </field>
       <field>
         <name>project</name>
         <path>project</path>
         <type>String</type>
+        <length>-1</length>
         <format/>
+        <trim_type>none</trim_type>
+        <precision>-1</precision>
         <currency/>
         <decimal/>
         <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
       </field>
       <field>
         <name>javaFileCount</name>
         <path>javaFileCount</path>
         <type>Integer</type>
+        <length>-1</length>
         <format/>
+        <trim_type>none</trim_type>
+        <precision>-1</precision>
         <currency/>
         <decimal/>
         <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
       </field>
       <field>
         <name>awesome</name>
         <path>awesome</path>
         <type>Boolean</type>
+        <length>-1</length>
         <format/>
+        <trim_type>none</trim_type>
+        <precision>-1</precision>
         <currency/>
         <decimal/>
         <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
       </field>
       <field>
         <name>used-apache-projects</name>
         <path>used-apache-projects</path>
         <type>String</type>
+        <length>-1</length>
         <format/>
+        <trim_type>none</trim_type>
+        <precision>-1</precision>
         <currency/>
         <decimal/>
         <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
       </field>
       <field>
         <name>statistics</name>
         <path>statistics</path>
         <type>String</type>
+        <length>-1</length>
         <format/>
+        <trim_type>none</trim_type>
+        <precision>-1</precision>
         <currency/>
         <decimal/>
         <group/>
-        <length>-1</length>
-        <precision>-1</precision>
-        <trim_type>none</trim_type>
       </field>
     </fields>
-    <limit>0</limit>
-    <IsInFields>N</IsInFields>
-    <IsAFile>N</IsAFile>
-    <YamlField/>
-    <attributes/>
+    <distribute>Y</distribute>
+    <copies>1</copies>
     <GUI>
-      <xloc>80</xloc>
-      <yloc>64</yloc>
+      <xloc>48</xloc>
+      <yloc>48</yloc>
     </GUI>
+    <description/>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
   </transform>
   <transform>
-    <name>validate</name>
     <type>Dummy</type>
-    <description/>
+    <name>validate</name>
     <distribute>Y</distribute>
-    <custom_distribution/>
     <copies>1</copies>
+    <GUI>
+      <xloc>192</xloc>
+      <yloc>48</yloc>
+    </GUI>
+    <description/>
     <partitioning>
       <method>none</method>
       <schema_name/>
     </partitioning>
     <attributes/>
-    <GUI>
-      <xloc>288</xloc>
-      <yloc>64</yloc>
-    </GUI>
   </transform>
-  <transform_error_handling>
-  </transform_error_handling>
+  <order>
+    <hop>
+      <from>files/yaml-input.yaml</from>
+      <to>validate</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <notepads/>
   <attributes/>
+  <transform_error_handling/>
 </pipeline>
diff --git a/integration-tests/transforms/datasets/golden-yaml-input-field.csv 
b/integration-tests/transforms/datasets/golden-yaml-input-field.csv
new file mode 100644
index 0000000000..bbc16a5dc0
--- /dev/null
+++ b/integration-tests/transforms/datasets/golden-yaml-input-field.csv
@@ -0,0 +1,3 @@
+id,name,version
+1,Spark,4.0.0
+2,Flink,1.20
diff --git a/integration-tests/transforms/datasets/golden-yaml-input-list.csv 
b/integration-tests/transforms/datasets/golden-yaml-input-list.csv
new file mode 100644
index 0000000000..fe705a8965
--- /dev/null
+++ b/integration-tests/transforms/datasets/golden-yaml-input-list.csv
@@ -0,0 +1,6 @@
+engine
+Spark
+Flink
+Beam
+Commons
+VFS
diff --git 
a/integration-tests/transforms/datasets/golden-yaml-input-multi-level.csv 
b/integration-tests/transforms/datasets/golden-yaml-input-multi-level.csv
new file mode 100644
index 0000000000..879fb44f21
--- /dev/null
+++ b/integration-tests/transforms/datasets/golden-yaml-input-multi-level.csv
@@ -0,0 +1,6 @@
+tableName,dataPagination,queryDataset
+t_user,100,"SELECT * FROM crm.t_user
+"
+t_customer,20,"SELECT * FROM crm.t_customer
+"
+t_order,30,SELECT * FROM crm.t_order
diff --git 
a/integration-tests/transforms/datasets/golden-yaml-input-multidoc.csv 
b/integration-tests/transforms/datasets/golden-yaml-input-multidoc.csv
new file mode 100644
index 0000000000..2f35075692
--- /dev/null
+++ b/integration-tests/transforms/datasets/golden-yaml-input-multidoc.csv
@@ -0,0 +1,4 @@
+name,type,distributed
+Spark,engine,Y
+Flink,engine,Y
+Janino,compiler,N
diff --git a/integration-tests/transforms/datasets/golden-yaml-input.csv 
b/integration-tests/transforms/datasets/golden-yaml-input.csv
index 6a7bac4601..84137e344f 100644
--- a/integration-tests/transforms/datasets/golden-yaml-input.csv
+++ b/integration-tests/transforms/datasets/golden-yaml-input.csv
@@ -1,2 +1,6 @@
 
organisation,acronym,project,javaFileCount,awesome,used-apache-projects,statistics
-The Apache Software Foundation,The ASF,Apache Hop,4447,Y,"[Spark, Flink, Beam, 
Commons, VFS]","{number-of-libs:  1159,number-of-messages-bundles:  
13025,integration-test-projects:  {count:  39,pipelines:  1032,workflows:  
498}}"
+The Apache Software Foundation,The ASF,Apache 
Hop,4447,Y,Spark,"{number-of-libs:  1159,number-of-messages-bundles:  
13025,integration-test-projects:  {count:  39,pipelines:  1032,workflows:  
498}}"
+The Apache Software Foundation,The ASF,Apache 
Hop,4447,Y,Flink,"{number-of-libs:  1159,number-of-messages-bundles:  
13025,integration-test-projects:  {count:  39,pipelines:  1032,workflows:  
498}}"
+The Apache Software Foundation,The ASF,Apache 
Hop,4447,Y,Beam,"{number-of-libs:  1159,number-of-messages-bundles:  
13025,integration-test-projects:  {count:  39,pipelines:  1032,workflows:  
498}}"
+The Apache Software Foundation,The ASF,Apache 
Hop,4447,Y,Commons,"{number-of-libs:  1159,number-of-messages-bundles:  
13025,integration-test-projects:  {count:  39,pipelines:  1032,workflows:  
498}}"
+The Apache Software Foundation,The ASF,Apache Hop,4447,Y,VFS,"{number-of-libs: 
 1159,number-of-messages-bundles:  13025,integration-test-projects:  {count:  
39,pipelines:  1032,workflows:  498}}"
diff --git a/integration-tests/transforms/files/yaml-input-list.yaml 
b/integration-tests/transforms/files/yaml-input-list.yaml
new file mode 100644
index 0000000000..48b5ab0370
--- /dev/null
+++ b/integration-tests/transforms/files/yaml-input-list.yaml
@@ -0,0 +1,25 @@
+#
+#
+# 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.
+#
+#
+#
+---
+  - Spark
+  - Flink
+  - Beam
+  - Commons
+  - VFS
diff --git a/integration-tests/transforms/files/yaml-input-multi-level.yaml 
b/integration-tests/transforms/files/yaml-input-multi-level.yaml
new file mode 100644
index 0000000000..875861fb35
--- /dev/null
+++ b/integration-tests/transforms/files/yaml-input-multi-level.yaml
@@ -0,0 +1,35 @@
+#
+#
+# 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.
+#
+#
+#
+
+tables:
+  - tableName: t_user
+    dataPagination: 100
+    queryDataset: |
+      SELECT * FROM crm.t_user
+
+  - tableName: t_customer
+    dataPagination: 20
+    queryDataset: |
+      SELECT * FROM crm.t_customer
+
+  - tableName: t_order
+    dataPagination: 30
+    queryDataset: |
+      SELECT * FROM crm.t_order
\ No newline at end of file
diff --git a/integration-tests/transforms/files/yaml-input-multidoc.yaml 
b/integration-tests/transforms/files/yaml-input-multidoc.yaml
new file mode 100644
index 0000000000..e9436455c8
--- /dev/null
+++ b/integration-tests/transforms/files/yaml-input-multidoc.yaml
@@ -0,0 +1,31 @@
+#
+#
+# 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.
+#
+#
+#
+---
+  name: "Spark"
+  type: "engine"
+  distributed: true
+---
+  name: "Flink"
+  type: "engine"
+  distributed: true
+---
+  name: "Janino"
+  type: "compiler"
+  distributed: false
diff --git a/integration-tests/transforms/0088-yaml-input.hwf 
b/integration-tests/transforms/main-0088-yaml-input.hwf
similarity index 87%
rename from integration-tests/transforms/0088-yaml-input.hwf
rename to integration-tests/transforms/main-0088-yaml-input.hwf
index 4440be7452..1c9bb28beb 100644
--- a/integration-tests/transforms/0088-yaml-input.hwf
+++ b/integration-tests/transforms/main-0088-yaml-input.hwf
@@ -18,7 +18,7 @@ limitations under the License.
 
 -->
 <workflow>
-  <name>0088-yaml-input</name>
+  <name>main-0088-yaml-input</name>
   <name_sync_with_filename>Y</name_sync_with_filename>
   <description/>
   <extended_description/>
@@ -58,6 +58,15 @@ limitations under the License.
         <test_name>
           <name>0088-yaml-input-validate UNIT</name>
         </test_name>
+        <test_name>
+          <name>0088-yaml-input-list-validate UNIT</name>
+        </test_name>
+        <test_name>
+          <name>0088-yaml-input-multidoc-validate UNIT</name>
+        </test_name>
+        <test_name>
+          <name>0088-yaml-input-field-validate UNIT</name>
+        </test_name>
       </test_names>
       <parallel>N</parallel>
       <xloc>272</xloc>
diff --git 
a/integration-tests/transforms/metadata/dataset/golden-yaml-input-field.json 
b/integration-tests/transforms/metadata/dataset/golden-yaml-input-field.json
new file mode 100644
index 0000000000..9a49b66009
--- /dev/null
+++ b/integration-tests/transforms/metadata/dataset/golden-yaml-input-field.json
@@ -0,0 +1,32 @@
+{
+  "base_filename": "golden-yaml-input-field.csv",
+  "name": "golden-yaml-input-field",
+  "description": "",
+  "dataset_fields": [
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 5,
+      "field_precision": 0,
+      "field_name": "id",
+      "field_format": "####0;-####0"
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 2,
+      "field_precision": -1,
+      "field_name": "name",
+      "field_format": ""
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 2,
+      "field_precision": -1,
+      "field_name": "version",
+      "field_format": ""
+    }
+  ],
+  "folder_name": ""
+}
diff --git 
a/integration-tests/transforms/metadata/dataset/golden-yaml-input-list.json 
b/integration-tests/transforms/metadata/dataset/golden-yaml-input-list.json
new file mode 100644
index 0000000000..a1b9b54a58
--- /dev/null
+++ b/integration-tests/transforms/metadata/dataset/golden-yaml-input-list.json
@@ -0,0 +1,16 @@
+{
+  "base_filename": "golden-yaml-input-list.csv",
+  "name": "golden-yaml-input-list",
+  "description": "",
+  "dataset_fields": [
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 2,
+      "field_precision": -1,
+      "field_name": "engine",
+      "field_format": ""
+    }
+  ],
+  "folder_name": ""
+}
diff --git 
a/integration-tests/transforms/metadata/dataset/golden-yaml-input-multi-level.json
 
b/integration-tests/transforms/metadata/dataset/golden-yaml-input-multi-level.json
new file mode 100644
index 0000000000..4b6827952d
--- /dev/null
+++ 
b/integration-tests/transforms/metadata/dataset/golden-yaml-input-multi-level.json
@@ -0,0 +1,32 @@
+{
+  "base_filename": "golden-yaml-input-multi-level.csv",
+  "name": "golden-yaml-input-multi-level",
+  "description": "",
+  "dataset_fields": [
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 2,
+      "field_precision": -1,
+      "field_name": "tableName",
+      "field_format": ""
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 5,
+      "field_precision": 0,
+      "field_name": "dataPagination",
+      "field_format": "####0;-####0"
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 2,
+      "field_precision": -1,
+      "field_name": "queryDataset",
+      "field_format": ""
+    }
+  ],
+  "folder_name": ""
+}
\ No newline at end of file
diff --git 
a/integration-tests/transforms/metadata/dataset/golden-yaml-input-multidoc.json 
b/integration-tests/transforms/metadata/dataset/golden-yaml-input-multidoc.json
new file mode 100644
index 0000000000..94463d76fc
--- /dev/null
+++ 
b/integration-tests/transforms/metadata/dataset/golden-yaml-input-multidoc.json
@@ -0,0 +1,32 @@
+{
+  "base_filename": "golden-yaml-input-multidoc.csv",
+  "name": "golden-yaml-input-multidoc",
+  "description": "",
+  "dataset_fields": [
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 2,
+      "field_precision": -1,
+      "field_name": "name",
+      "field_format": ""
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 2,
+      "field_precision": -1,
+      "field_name": "type",
+      "field_format": ""
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 4,
+      "field_precision": -1,
+      "field_name": "distributed",
+      "field_format": ""
+    }
+  ],
+  "folder_name": ""
+}
diff --git 
a/integration-tests/transforms/metadata/unit-test/0088-yaml-input-field-validate
 UNIT.json 
b/integration-tests/transforms/metadata/unit-test/0088-yaml-input-field-validate
 UNIT.json
new file mode 100644
index 0000000000..7e72d059cd
--- /dev/null
+++ 
b/integration-tests/transforms/metadata/unit-test/0088-yaml-input-field-validate
 UNIT.json  
@@ -0,0 +1,38 @@
+{
+  "database_replacements": [],
+  "autoOpening": true,
+  "description": "",
+  "persist_filename": "",
+  "test_type": "UNIT_TEST",
+  "variableValues": [],
+  "basePath": "${HOP_UNIT_TESTS_FOLDER}",
+  "golden_data_sets": [
+    {
+      "field_mappings": [
+        {
+          "transform_field": "id",
+          "data_set_field": "id"
+        },
+        {
+          "transform_field": "name",
+          "data_set_field": "name"
+        },
+        {
+          "transform_field": "version",
+          "data_set_field": "version"
+        }
+      ],
+      "field_order": [
+        "id",
+        "name",
+        "version"
+      ],
+      "data_set_name": "golden-yaml-input-field",
+      "transform_name": "validate"
+    }
+  ],
+  "input_data_sets": [],
+  "name": "0088-yaml-input-field-validate UNIT",
+  "trans_test_tweaks": [],
+  "pipeline_filename": "./0088-yaml-input-field.hpl"
+}
diff --git 
a/integration-tests/transforms/metadata/unit-test/0088-yaml-input-list-validate 
UNIT.json 
b/integration-tests/transforms/metadata/unit-test/0088-yaml-input-list-validate 
UNIT.json
new file mode 100644
index 0000000000..b0cbd9976e
--- /dev/null
+++ 
b/integration-tests/transforms/metadata/unit-test/0088-yaml-input-list-validate 
UNIT.json   
@@ -0,0 +1,28 @@
+{
+  "database_replacements": [],
+  "autoOpening": true,
+  "description": "",
+  "persist_filename": "",
+  "test_type": "UNIT_TEST",
+  "variableValues": [],
+  "basePath": "${HOP_UNIT_TESTS_FOLDER}",
+  "golden_data_sets": [
+    {
+      "field_mappings": [
+        {
+          "transform_field": "engine",
+          "data_set_field": "engine"
+        }
+      ],
+      "field_order": [
+        "engine"
+      ],
+      "data_set_name": "golden-yaml-input-list",
+      "transform_name": "validate"
+    }
+  ],
+  "input_data_sets": [],
+  "name": "0088-yaml-input-list-validate UNIT",
+  "trans_test_tweaks": [],
+  "pipeline_filename": "./0088-yaml-input-list.hpl"
+}
diff --git 
a/integration-tests/transforms/metadata/unit-test/0088-yaml-input-multi-level 
UNIT.json 
b/integration-tests/transforms/metadata/unit-test/0088-yaml-input-multi-level 
UNIT.json
new file mode 100644
index 0000000000..4ad218273d
--- /dev/null
+++ 
b/integration-tests/transforms/metadata/unit-test/0088-yaml-input-multi-level 
UNIT.json     
@@ -0,0 +1,38 @@
+{
+  "database_replacements": [],
+  "autoOpening": true,
+  "description": "",
+  "persist_filename": "",
+  "test_type": "UNIT_TEST",
+  "variableValues": [],
+  "basePath": "${HOP_UNIT_TESTS_FOLDER}",
+  "golden_data_sets": [
+    {
+      "field_mappings": [
+        {
+          "transform_field": "tableName",
+          "data_set_field": "tableName"
+        },
+        {
+          "transform_field": "dataPagination",
+          "data_set_field": "dataPagination"
+        },
+        {
+          "transform_field": "queryDataset",
+          "data_set_field": "queryDataset"
+        }
+      ],
+      "field_order": [
+        "tableName",
+        "dataPagination",
+        "queryDataset"
+      ],
+      "data_set_name": "golden-yaml-input-multi-level",
+      "transform_name": "validate"
+    }
+  ],
+  "input_data_sets": [],
+  "name": "0088-yaml-input-multi-level UNIT",
+  "trans_test_tweaks": [],
+  "pipeline_filename": "./0088-yaml-input-multi-level.hpl"
+}
\ No newline at end of file
diff --git 
a/integration-tests/transforms/metadata/unit-test/0088-yaml-input-multidoc-validate
 UNIT.json 
b/integration-tests/transforms/metadata/unit-test/0088-yaml-input-multidoc-validate
 UNIT.json
new file mode 100644
index 0000000000..c5d7fed07a
--- /dev/null
+++ 
b/integration-tests/transforms/metadata/unit-test/0088-yaml-input-multidoc-validate
 UNIT.json       
@@ -0,0 +1,38 @@
+{
+  "database_replacements": [],
+  "autoOpening": true,
+  "description": "",
+  "persist_filename": "",
+  "test_type": "UNIT_TEST",
+  "variableValues": [],
+  "basePath": "${HOP_UNIT_TESTS_FOLDER}",
+  "golden_data_sets": [
+    {
+      "field_mappings": [
+        {
+          "transform_field": "name",
+          "data_set_field": "name"
+        },
+        {
+          "transform_field": "type",
+          "data_set_field": "type"
+        },
+        {
+          "transform_field": "distributed",
+          "data_set_field": "distributed"
+        }
+      ],
+      "field_order": [
+        "name",
+        "type",
+        "distributed"
+      ],
+      "data_set_name": "golden-yaml-input-multidoc",
+      "transform_name": "validate"
+    }
+  ],
+  "input_data_sets": [],
+  "name": "0088-yaml-input-multidoc-validate UNIT",
+  "trans_test_tweaks": [],
+  "pipeline_filename": "./0088-yaml-input-multidoc.hpl"
+}
diff --git a/plugins/transforms/yamlinput/pom.xml 
b/plugins/transforms/yamlinput/pom.xml
index b365b45faa..b7233803d9 100644
--- a/plugins/transforms/yamlinput/pom.xml
+++ b/plugins/transforms/yamlinput/pom.xml
@@ -42,6 +42,12 @@
     </dependencyManagement>
 
     <dependencies>
+        <dependency>
+            <groupId>com.jayway.jsonpath</groupId>
+            <artifactId>json-path</artifactId>
+            <version>${json-path.version}</version>
+            <scope>provided</scope>
+        </dependency>
         <dependency>
             <groupId>org.yaml</groupId>
             <artifactId>snakeyaml</artifactId>
diff --git 
a/plugins/transforms/yamlinput/src/main/java/org/apache/hop/pipeline/transforms/yamlinput/YamlInput.java
 
b/plugins/transforms/yamlinput/src/main/java/org/apache/hop/pipeline/transforms/yamlinput/YamlInput.java
index acb70b1f2a..93a7cfe0cc 100644
--- 
a/plugins/transforms/yamlinput/src/main/java/org/apache/hop/pipeline/transforms/yamlinput/YamlInput.java
+++ 
b/plugins/transforms/yamlinput/src/main/java/org/apache/hop/pipeline/transforms/yamlinput/YamlInput.java
@@ -132,12 +132,12 @@ public class YamlInput extends 
BaseTransform<YamlInputMeta, YamlInputData> {
                 PKG, "YamlInput.Log.YAMLStream", meta.getYamlField(), 
fieldValue));
       }
 
-      if (meta.isSourceFile()) {
-
-        // source is a file.
+      data.yaml = new YamlReader();
+      data.yaml.setFieldPaths(data.fieldPaths);
 
+      // source is a file.
+      if (meta.isSourceFile()) {
         FileObject yamlFile = HopVfs.getFileObject(fieldValue, variables);
-        data.yaml = new YamlReader();
         data.yaml.loadFile(yamlFile);
         dataVolumeIn =
             (dataVolumeIn != null ? dataVolumeIn : 0L) + 
data.yaml.getBytesReadFromFile();
@@ -145,7 +145,6 @@ public class YamlInput extends BaseTransform<YamlInputMeta, 
YamlInputData> {
 
         addFileToResultFilesName(data.yaml.getFile());
       } else {
-        data.yaml = new YamlReader();
         data.yaml.loadString(fieldValue);
       }
     } catch (Exception e) {
@@ -235,6 +234,7 @@ public class YamlInput extends BaseTransform<YamlInputMeta, 
YamlInputData> {
         // We have a file
         // define a YAML reader and load file
         data.yaml = new YamlReader();
+        data.yaml.setFieldPaths(data.fieldPaths);
         data.yaml.loadFile(data.file);
         dataVolumeIn =
             (dataVolumeIn != null ? dataVolumeIn : 0L) + 
data.yaml.getBytesReadFromFile();
@@ -416,14 +416,17 @@ public class YamlInput extends 
BaseTransform<YamlInputMeta, YamlInputData> {
     if (super.init()) {
       data.rowIndex = 1L;
       data.nrInputFields = meta.getInputFields().size();
+      data.fieldPaths = new String[data.nrInputFields];
 
       data.rowMeta = new RowMeta();
       for (int i = 0; i < data.nrInputFields; i++) {
         YamlInputField field = meta.getInputFields().get(i);
-        String path = resolve(field.getPath());
+        String fieldName = resolve(field.getName());
+        // resolve config yaml field path(.eg: $.table.name)
+        data.fieldPaths[i] = YamlPathResolver.resolvePath(this, 
field.getPath());
 
         try {
-          IValueMeta valueMeta = ValueMetaFactory.createValueMeta(path, 
field.getType());
+          IValueMeta valueMeta = ValueMetaFactory.createValueMeta(fieldName, 
field.getType());
           valueMeta.setTrimType(field.getTrimType());
           data.rowMeta.addValueMeta(valueMeta);
         } catch (Exception e) {
diff --git 
a/plugins/transforms/yamlinput/src/main/java/org/apache/hop/pipeline/transforms/yamlinput/YamlInputData.java
 
b/plugins/transforms/yamlinput/src/main/java/org/apache/hop/pipeline/transforms/yamlinput/YamlInputData.java
index 0b53fbad96..7a798bb2b6 100644
--- 
a/plugins/transforms/yamlinput/src/main/java/org/apache/hop/pipeline/transforms/yamlinput/YamlInputData.java
+++ 
b/plugins/transforms/yamlinput/src/main/java/org/apache/hop/pipeline/transforms/yamlinput/YamlInputData.java
@@ -22,6 +22,7 @@ import org.apache.hop.core.fileinput.FileInputList;
 import org.apache.hop.core.row.IRowMeta;
 import org.apache.hop.pipeline.transform.BaseTransformData;
 
+/** yaml input data */
 @SuppressWarnings("java:S1104")
 public class YamlInputData extends BaseTransformData {
   public IRowMeta outputRowMeta;
@@ -45,6 +46,9 @@ public class YamlInputData extends BaseTransformData {
 
   public IRowMeta rowMeta;
 
+  /** yaml field path[] */
+  public String[] fieldPaths;
+
   public YamlInputData() {
     super();
 
diff --git 
a/plugins/transforms/yamlinput/src/main/java/org/apache/hop/pipeline/transforms/yamlinput/YamlInputDialog.java
 
b/plugins/transforms/yamlinput/src/main/java/org/apache/hop/pipeline/transforms/yamlinput/YamlInputDialog.java
index 8dbf1b40fb..b2aacde490 100644
--- 
a/plugins/transforms/yamlinput/src/main/java/org/apache/hop/pipeline/transforms/yamlinput/YamlInputDialog.java
+++ 
b/plugins/transforms/yamlinput/src/main/java/org/apache/hop/pipeline/transforms/yamlinput/YamlInputDialog.java
@@ -17,6 +17,7 @@
 
 package org.apache.hop.pipeline.transforms.yamlinput;
 
+import java.util.List;
 import org.apache.hop.core.Const;
 import org.apache.hop.core.Props;
 import org.apache.hop.core.exception.HopException;
@@ -993,13 +994,14 @@ public class YamlInputDialog extends BaseTransformDialog {
         yaml = new YamlReader();
         yaml.loadFile(inputList.getFile(0));
         RowMeta row = yaml.getFields();
+        List<String> paths = yaml.getDiscoveredPaths();
 
-        for (int i = 0; i < row.size(); i++) {
+        for (int i = 0; i < paths.size(); i++) {
           IValueMeta value = row.getValueMeta(i);
 
           TableItem item = new TableItem(wFields.table, SWT.NONE);
           item.setText(1, value.getName());
-          item.setText(2, value.getName());
+          item.setText(2, paths.get(i));
           item.setText(3, value.getTypeDesc());
         }
         wFields.removeEmptyRows();
diff --git 
a/plugins/transforms/yamlinput/src/main/java/org/apache/hop/pipeline/transforms/yamlinput/YamlPathResolver.java
 
b/plugins/transforms/yamlinput/src/main/java/org/apache/hop/pipeline/transforms/yamlinput/YamlPathResolver.java
new file mode 100644
index 0000000000..6b1b0253dc
--- /dev/null
+++ 
b/plugins/transforms/yamlinput/src/main/java/org/apache/hop/pipeline/transforms/yamlinput/YamlPathResolver.java
@@ -0,0 +1,64 @@
+/*
+ * 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.yamlinput;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.hop.core.util.StringUtil;
+import org.apache.hop.core.util.Utils;
+import org.apache.hop.core.variables.IVariables;
+
+/** Normalizes and resolves YAML/JSON-style path expressions for JsonPath 
evaluation. */
+public final class YamlPathResolver {
+  public static final String DOLLAR = "$";
+
+  private YamlPathResolver() {}
+
+  /**
+   * Turns a legacy flat key or dotted path into a JsonPath expression. Paths 
that already start
+   * with {@code $} are returned unchanged.
+   */
+  public static String normalize(String path) {
+    if (Utils.isEmpty(path)) {
+      return DOLLAR;
+    }
+
+    if (path.startsWith(DOLLAR)) {
+      return path;
+    }
+    return "$." + path;
+  }
+
+  /**
+   * Substitutes pipeline variables in a path without mangling JsonPath syntax 
such as {@code $[*]}.
+   */
+  public static String resolvePath(IVariables variables, String path) {
+    if (Utils.isEmpty(path) || variables == null) {
+      return normalize(path);
+    }
+
+    Map<String, String> variableMap = new HashMap<>();
+    for (String name : variables.getVariableNames()) {
+      variableMap.put(name, variables.getVariable(name));
+    }
+
+    String substituted =
+        StringUtil.substituteUnix(StringUtil.substituteWindows(path, 
variableMap), variableMap);
+    return normalize(substituted);
+  }
+}
diff --git 
a/plugins/transforms/yamlinput/src/main/java/org/apache/hop/pipeline/transforms/yamlinput/YamlReader.java
 
b/plugins/transforms/yamlinput/src/main/java/org/apache/hop/pipeline/transforms/yamlinput/YamlReader.java
index d0acefd6da..6fba1d6108 100644
--- 
a/plugins/transforms/yamlinput/src/main/java/org/apache/hop/pipeline/transforms/yamlinput/YamlReader.java
+++ 
b/plugins/transforms/yamlinput/src/main/java/org/apache/hop/pipeline/transforms/yamlinput/YamlReader.java
@@ -17,14 +17,22 @@
 
 package org.apache.hop.pipeline.transforms.yamlinput;
 
+import com.jayway.jsonpath.Configuration;
+import com.jayway.jsonpath.JsonPath;
+import com.jayway.jsonpath.Option;
+import com.jayway.jsonpath.ReadContext;
 import java.io.IOException;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.sql.Timestamp;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Deque;
 import java.util.Iterator;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import lombok.Getter;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.vfs2.FileObject;
@@ -47,6 +55,10 @@ import org.yaml.snakeyaml.Yaml;
 public class YamlReader {
   private static final String DEFAULT_LIST_VALUE_NAME = "Value";
 
+  private static final Configuration JSON_PATH_CONFIG =
+      Configuration.defaultConfiguration()
+          .addOptions(Option.SUPPRESS_EXCEPTIONS, 
Option.DEFAULT_PATH_LEAF_TO_NULL);
+
   private String string;
   @Getter private FileObject file;
 
@@ -66,6 +78,14 @@ public class YamlReader {
   private boolean useMap;
   @Getter private Yaml yaml;
 
+  /** yaml field path */
+  private String[] fieldPaths;
+
+  private JsonPath[] compiledPaths;
+  private String[] discoveredFieldPaths;
+
+  private final Deque<Object[]> pendingRows = new ArrayDeque<>();
+
   /** Bytes read from the last loaded file (for data volume tracking). */
   @Getter private long bytesReadFromFile;
 
@@ -78,6 +98,26 @@ public class YamlReader {
     this.yaml = new Yaml();
   }
 
+  /**
+   * Sets the YAML field paths to be extracted and pre-compiles them into 
{@link JsonPath} instances
+   * for better runtime performance.
+   *
+   * @param paths the array of field paths to extract; {@code null} clears all 
configured paths
+   */
+  public void setFieldPaths(String[] paths) {
+    if (paths == null) {
+      this.fieldPaths = null;
+      this.compiledPaths = null;
+      return;
+    }
+
+    this.fieldPaths = paths.clone();
+    this.compiledPaths = new JsonPath[paths.length];
+    for (int i = 0; i < paths.length; i++) {
+      this.compiledPaths[i] = 
JsonPath.compile(YamlPathResolver.normalize(paths[i]));
+    }
+  }
+
   public void loadFile(FileObject file) throws Exception {
     this.file = file;
 
@@ -107,6 +147,14 @@ public class YamlReader {
 
   /** get row */
   public Object[] getRow(IRowMeta rowMeta) {
+    if (!pendingRows.isEmpty()) {
+      Object[] row = pendingRows.poll();
+      if (pendingRows.isEmpty()) {
+        finishDocument();
+      }
+      return row;
+    }
+
     if (document == null) {
       getNextDocument();
     }
@@ -122,19 +170,41 @@ public class YamlReader {
     return row;
   }
 
+  /**
+   * Ensures that the configured field paths have been compiled into {@link 
JsonPath} instances.
+   *
+   * @param rowMeta the row metadata used to determine field paths when they 
have not been
+   *     explicitly configured
+   */
+  private void ensurePathsCompiled(IRowMeta rowMeta) {
+    if (compiledPaths != null && compiledPaths.length == rowMeta.size()) {
+      return;
+    }
+
+    String[] paths = new String[rowMeta.size()];
+    if (discoveredFieldPaths != null && discoveredFieldPaths.length == 
rowMeta.size()) {
+      System.arraycopy(discoveredFieldPaths, 0, paths, 0, paths.length);
+    } else {
+      for (int i = 0; i < rowMeta.size(); i++) {
+        paths[i] = rowMeta.getValueMeta(i).getName();
+      }
+    }
+    setFieldPaths(paths);
+  }
+
   private Object[] fetchRow(IRowMeta rowMeta) {
+    ensurePathsCompiled(rowMeta);
+
     if (isMapUsed()) {
-      return processMapRow(rowMeta, (Map<?, ?>) document);
+      return processMapRow(rowMeta, document, false);
     }
 
     return processListRow(rowMeta);
   }
 
   private Object[] handleCurrentListValue(IRowMeta rowMeta) {
-    List<?> list = (List<?>) document;
-
-    if (list.size() == 1 && list.getFirst() instanceof Map<?, ?> map) {
-      return processMapRow(rowMeta, map);
+    if (dataList instanceof Map<?, ?>) {
+      return processMapRow(rowMeta, dataList, true);
     }
 
     IValueMeta valueMeta = rowMeta.getValueMeta(0);
@@ -151,20 +221,92 @@ public class YamlReader {
     return row;
   }
 
-  private Object[] processMapRow(IRowMeta rowMeta, Map<?, ?> map) {
-    Object[] row = new Object[rowMeta.size()];
+  private Object[] processMapRow(IRowMeta rowMeta, Object root, boolean 
listElement) {
+    if (pendingRows.isEmpty()) {
+      prepareRowsFromPaths(rowMeta, root, listElement);
+    }
 
-    for (int i = 0; i < rowMeta.size(); i++) {
-      IValueMeta valueMeta = rowMeta.getValueMeta(i);
+    Object[] row = pendingRows.poll();
+    if (pendingRows.isEmpty()) {
+      finishDocument();
+    }
+    return row == null ? new Object[0] : row;
+  }
 
-      Object value =
-          Utils.isEmpty(valueMeta.getName()) ? document.toString() : 
map.get(valueMeta.getName());
+  private void prepareRowsFromPaths(IRowMeta rowMeta, Object root, boolean 
listElement) {
+    List<List<Object>> columnValues = new ArrayList<>(compiledPaths.length);
+    int rowCount = 1;
 
-      row[i] = getValue(value, valueMeta);
+    for (int pathIndex = 0; pathIndex < compiledPaths.length; pathIndex++) {
+      JsonPath path = pathForRoot(compiledPaths[pathIndex], 
fieldPaths[pathIndex], listElement);
+      List<Object> values = readPathAsList(root, path);
+      if (values.size() > rowCount) {
+        rowCount = values.size();
+      }
+      columnValues.add(values);
     }
 
-    finishDocument();
-    return row;
+    for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
+      Object[] row = new Object[rowMeta.size()];
+      for (int col = 0; col < rowMeta.size(); col++) {
+        List<Object> values = columnValues.get(col);
+        Object raw = pickValue(values, rowIndex, rowCount);
+        row[col] = getValue(raw, rowMeta.getValueMeta(col));
+      }
+      pendingRows.add(row);
+    }
+  }
+
+  private static JsonPath pathForRoot(
+      JsonPath compiledPath, String originalPath, boolean listElement) {
+    if (!listElement || originalPath == null || !originalPath.contains("[*]")) 
{
+      return compiledPath;
+    }
+
+    String adapted = originalPath.replaceFirst("\\$\\[\\*]", "\\$");
+    return JsonPath.compile(YamlPathResolver.normalize(adapted));
+  }
+
+  private static Object pickValue(List<Object> values, int rowIndex, int 
rowCount) {
+    if (values == null || values.isEmpty()) {
+      return null;
+    }
+
+    if (values.size() == 1 && rowCount > 1) {
+      return values.getFirst();
+    }
+    if (rowIndex < values.size()) {
+      return values.get(rowIndex);
+    }
+    return null;
+  }
+
+  private List<Object> readPathAsList(Object root, JsonPath path) {
+    if (root == null) {
+      return List.of((Object) null);
+    }
+
+    try {
+      ReadContext context = JsonPath.using(JSON_PATH_CONFIG).parse(root);
+      Object result = context.read(path);
+      return toValueList(result);
+    } catch (Exception e) {
+      return List.of((Object) null);
+    }
+  }
+
+  private static List<Object> toValueList(Object result) {
+    if (result == null) {
+      return List.of((Object) null);
+    }
+
+    if (result instanceof List<?> list) {
+      if (list.isEmpty()) {
+        return List.of((Object) null);
+      }
+      return new ArrayList<>(list);
+    }
+    return List.of(result);
   }
 
   private Object[] advanceListIterator() {
@@ -178,6 +320,7 @@ public class YamlReader {
   }
 
   private void getNextDocument() {
+    pendingRows.clear();
     // See if we have another document
     if (this.documentIt.hasNext()) {
       // We have another document
@@ -237,6 +380,7 @@ public class YamlReader {
 
   private void finishDocument() {
     this.document = null;
+    pendingRows.clear();
   }
 
   private boolean isFinishedDocument() {
@@ -345,39 +489,80 @@ public class YamlReader {
   /** get fields. */
   public RowMeta getFields() {
     RowMeta rowMeta = new RowMeta();
-
-    for (Object data : documents) {
-      if (data instanceof Map<?, ?> map) {
-        appendFromMap(rowMeta, map);
-      } else if (data instanceof List<?> list) {
-        appendFromList(rowMeta, list);
+    List<String> paths = getDiscoveredPaths();
+    discoveredFieldPaths = paths.toArray(new String[0]);
+
+    for (String path : paths) {
+      Object sample = null;
+      for (Object data : documents) {
+        sample = readSampleValue(data, path);
+        if (sample != null) {
+          break;
+        }
       }
+      addField(rowMeta, path, sample);
     }
 
     return rowMeta;
   }
 
-  private void appendFromList(RowMeta rowMeta, List<?> list) {
-    if (list.isEmpty()) {
-      return;
+  /** Returns JsonPath expressions discovered in the loaded YAML documents. */
+  public List<String> getDiscoveredPaths() {
+    Set<String> paths = new LinkedHashSet<>();
+    for (Object data : documents) {
+      collectPaths(data, YamlPathResolver.DOLLAR, paths);
     }
+    return new ArrayList<>(paths);
+  }
 
-    Object first = list.getFirst();
-    if (list.size() == 1 && first instanceof Map<?, ?> map) {
-      appendFromMap(rowMeta, map);
-    } else {
-      addField(rowMeta, DEFAULT_LIST_VALUE_NAME, first);
+  private Object readSampleValue(Object root, String path) {
+    if (root == null) {
+      return null;
     }
+    List<Object> values = readPathAsList(root, JsonPath.compile(path));
+    return values.isEmpty() ? null : values.getFirst();
   }
 
-  private void appendFromMap(RowMeta rowMeta, Map<?, ?> map) {
-    for (Map.Entry<?, ?> entry : map.entrySet()) {
-      addField(rowMeta, entry.getKey(), entry.getValue());
+  private void collectPaths(Object node, String prefix, Set<String> paths) {
+    if (node instanceof Map<?, ?> map) {
+      for (Map.Entry<?, ?> entry : map.entrySet()) {
+        String key = String.valueOf(entry.getKey());
+        String segment = formatPathSegment(key);
+        String childPath =
+            YamlPathResolver.DOLLAR.equals(prefix)
+                ? prefix + "." + segment
+                : prefix + "." + segment;
+        Object value = entry.getValue();
+        if (value instanceof Map || value instanceof List) {
+          collectPaths(value, childPath, paths);
+        } else {
+          paths.add(childPath);
+        }
+      }
+    } else if (node instanceof List<?> list) {
+      if (!list.isEmpty()) {
+        Object first = list.getFirst();
+        if (first instanceof Map || first instanceof List) {
+          collectPaths(first, prefix + "[*]", paths);
+        } else {
+          paths.add(prefix + "[*]");
+        }
+      }
+    } else if (YamlPathResolver.DOLLAR.equals(prefix)) {
+      paths.add(YamlPathResolver.DOLLAR);
     }
   }
 
-  private void addField(RowMeta rowMeta, Object key, Object value) {
-    String fieldName = String.valueOf(key);
+  private static String formatPathSegment(String key) {
+    if (key.contains(".") || key.contains(" ") || key.contains("[")) {
+      return "['" + key.replace("'", "\\'") + "']";
+    }
+
+    return key;
+  }
+
+  private void addField(RowMeta rowMeta, String path, Object value) {
+    String fieldName = fieldNameFromPath(path);
 
     IValueMeta valueMeta;
     try {
@@ -388,4 +573,33 @@ public class YamlReader {
 
     rowMeta.addValueMeta(valueMeta);
   }
+
+  static String fieldNameFromPath(String path) {
+    if (Utils.isEmpty(path) || YamlPathResolver.DOLLAR.equals(path)) {
+      return path;
+    }
+    if ("$[*]".equals(path)) {
+      return DEFAULT_LIST_VALUE_NAME;
+    }
+
+    int bracket = path.lastIndexOf("['");
+    if (bracket >= 0) {
+      int quoteEnd = path.indexOf("']", bracket);
+      if (quoteEnd > bracket) {
+        return path.substring(bracket + 2, quoteEnd).replace("\\'", "'");
+      }
+    }
+
+    int dot = path.lastIndexOf('.');
+    if (dot >= 0 && dot < path.length() - 1) {
+      String leaf = path.substring(dot + 1);
+      int open = leaf.indexOf('[');
+      return open >= 0 ? leaf.substring(0, open) : leaf;
+    }
+
+    if (path.startsWith(YamlPathResolver.DOLLAR)) {
+      return path.substring(1);
+    }
+    return path;
+  }
 }
diff --git 
a/plugins/transforms/yamlinput/src/main/resources/org/apache/hop/pipeline/transforms/yamlinput/messages/messages_en_US.properties
 
b/plugins/transforms/yamlinput/src/main/resources/org/apache/hop/pipeline/transforms/yamlinput/messages/messages_en_US.properties
index cda9aa50ba..9da646c273 100644
--- 
a/plugins/transforms/yamlinput/src/main/resources/org/apache/hop/pipeline/transforms/yamlinput/messages/messages_en_US.properties
+++ 
b/plugins/transforms/yamlinput/src/main/resources/org/apache/hop/pipeline/transforms/yamlinput/messages/messages_en_US.properties
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-YamlInput.Description=Read YAML source (file or stream) parse them and convert 
them to rows and writes these to one or more output.
+YamlInput.Description=Read YAML source (file or stream), extract fields with 
JsonPath expressions, and output rows.
 YamlInput.Error.FileSizeZero=File [{0}] is empty\!
 YamlInput.ErrorInTransformRunning=Error reading from Yaml source\! {0}
 YamlInput.Exception.CouldnotFindField=Could not find field ''{0}'' in row\!
@@ -61,8 +61,8 @@ YamlInputDialog.FieldsTable.Name.Column.Tooltip=Field name in 
the returned strea
 YamlInputDialog.FieldsTable.Precision.Column=Precision
 YamlInputDialog.FieldsTable.TrimType.Column=Trim type
 YamlInputDialog.FieldsTable.Type.Column=Type
-YamlInputDialog.FieldsTable.XPath.Column=Key
-YamlInputDialog.FieldsTable.XPath.Column.Tooltip=Path to extract from the files
+YamlInputDialog.FieldsTable.XPath.Column=Path
+YamlInputDialog.FieldsTable.XPath.Column.Tooltip=JsonPath expression to 
extract from the YAML (e.g. $.table.name or $.tables[0].name). Legacy flat keys 
such as key1 are treated as $.key1.
 YamlInputDialog.File.Tab=File
 YamlInputDialog.Filename.Label=File or directory
 YamlInputDialog.FilenameAdd.Button=&Add
diff --git 
a/plugins/transforms/yamlinput/src/test/java/org/apache/hop/pipeline/transforms/yamlinput/YamlInputTests.java
 
b/plugins/transforms/yamlinput/src/test/java/org/apache/hop/pipeline/transforms/yamlinput/YamlInputTests.java
index d996d88e20..8f4723f88f 100644
--- 
a/plugins/transforms/yamlinput/src/test/java/org/apache/hop/pipeline/transforms/yamlinput/YamlInputTests.java
+++ 
b/plugins/transforms/yamlinput/src/test/java/org/apache/hop/pipeline/transforms/yamlinput/YamlInputTests.java
@@ -81,6 +81,7 @@ class YamlInputTests {
   @Test
   void testInit_shouldBuildRowMeta() {
     YamlInputField field = new YamlInputField();
+    field.setName("user_name");
     field.setPath("user.name");
     field.setType(IValueMeta.TYPE_STRING);
     field.setTrimType(YamlInputField.TYPE_TRIM_BOTH);
@@ -98,6 +99,8 @@ class YamlInputTests {
 
     assertNotNull(input.getData().rowMeta);
     assertEquals(1, input.getData().nrInputFields);
+    assertEquals("user_name", 
input.getData().rowMeta.getValueMeta(0).getName());
+    assertEquals("$.user.name", input.getData().fieldPaths[0]);
   }
 
   @Test
diff --git 
a/plugins/transforms/yamlinput/src/test/java/org/apache/hop/pipeline/transforms/yamlinput/YamlPathResolverTests.java
 
b/plugins/transforms/yamlinput/src/test/java/org/apache/hop/pipeline/transforms/yamlinput/YamlPathResolverTests.java
new file mode 100644
index 0000000000..92d43a2c10
--- /dev/null
+++ 
b/plugins/transforms/yamlinput/src/test/java/org/apache/hop/pipeline/transforms/yamlinput/YamlPathResolverTests.java
@@ -0,0 +1,71 @@
+/*
+ * 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.yamlinput;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.apache.hop.core.HopEnvironment;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.variables.Variables;
+import org.apache.hop.junit.rules.RestoreHopEnvironmentExtension;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+@ExtendWith(RestoreHopEnvironmentExtension.class)
+class YamlPathResolverTests {
+
+  @BeforeAll
+  static void init() throws HopException {
+    HopEnvironment.init();
+  }
+
+  @Test
+  void normalize_legacyFlatKey() {
+    assertEquals("$.key1", YamlPathResolver.normalize("key1"));
+  }
+
+  @Test
+  void normalize_dottedPath() {
+    assertEquals("$.table.name", YamlPathResolver.normalize("table.name"));
+  }
+
+  @Test
+  void normalize_jsonPathUnchanged() {
+    assertEquals("$.table.name", YamlPathResolver.normalize("$.table.name"));
+    assertEquals("$.tables[0].name", 
YamlPathResolver.normalize("$.tables[0].name"));
+    assertEquals("$[*].name", YamlPathResolver.normalize("$[*].name"));
+  }
+
+  @Test
+  void normalize_emptyPath() {
+    assertEquals(YamlPathResolver.DOLLAR, YamlPathResolver.normalize(""));
+    assertEquals(YamlPathResolver.DOLLAR, YamlPathResolver.normalize(null));
+  }
+
+  @Test
+  void resolvePath_substitutesVariablesWithoutManglingWildcards() {
+    Variables variables = new Variables();
+    variables.setVariable("TABLE", "table");
+
+    assertEquals(
+        "$.table.name",
+        YamlPathResolver.resolvePath(variables, "$." + 
variables.getVariable("TABLE") + ".name"));
+    assertEquals("$.items[*].id", YamlPathResolver.resolvePath(variables, 
"$.items[*].id"));
+  }
+}
diff --git 
a/plugins/transforms/yamlinput/src/test/java/org/apache/hop/pipeline/transforms/yamlinput/YamlReaderTests.java
 
b/plugins/transforms/yamlinput/src/test/java/org/apache/hop/pipeline/transforms/yamlinput/YamlReaderTests.java
index fed1ede508..08e3050403 100644
--- 
a/plugins/transforms/yamlinput/src/test/java/org/apache/hop/pipeline/transforms/yamlinput/YamlReaderTests.java
+++ 
b/plugins/transforms/yamlinput/src/test/java/org/apache/hop/pipeline/transforms/yamlinput/YamlReaderTests.java
@@ -25,11 +25,14 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import java.io.FileWriter;
 import java.nio.file.Path;
 import java.util.Date;
+import java.util.List;
 import org.apache.commons.vfs2.FileObject;
 import org.apache.hop.core.HopEnvironment;
 import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.exception.HopPluginException;
 import org.apache.hop.core.row.IValueMeta;
 import org.apache.hop.core.row.RowMeta;
+import org.apache.hop.core.row.value.ValueMetaFactory;
 import org.apache.hop.core.vfs.HopVfs;
 import org.apache.hop.junit.rules.RestoreHopEnvironmentExtension;
 import org.junit.jupiter.api.BeforeAll;
@@ -156,7 +159,7 @@ class YamlReaderTests {
   }
 
   @Test
-  void testNestedMapToString() {
+  void testNestedMapToString() throws HopPluginException {
     String yaml = """
                                person:
                                  name: Tom
@@ -165,7 +168,10 @@ class YamlReaderTests {
 
     reader.loadString(yaml);
 
-    RowMeta rowMeta = reader.getFields();
+    RowMeta rowMeta = new RowMeta();
+    reader.setFieldPaths(new String[] {"person"});
+    rowMeta.addValueMeta(ValueMetaFactory.createValueMeta("person", 
IValueMeta.TYPE_STRING));
+
     Object[] row = reader.getRow(rowMeta);
 
     assertNotNull(row[0]);
@@ -173,6 +179,144 @@ class YamlReaderTests {
     assertTrue(row[0].toString().contains("age"));
   }
 
+  @Test
+  void testJsonPath_nestedObjectFields() throws Exception {
+    String yaml = """
+                               table:
+                                 name: t_user
+                                 startId: 1000
+                               """;
+
+    reader.loadString(yaml);
+
+    RowMeta rowMeta =
+        buildRowMeta(
+            new String[] {"table_name", "start_id"},
+            new String[] {"$.table.name", "$.table.startId"},
+            new int[] {IValueMeta.TYPE_STRING, IValueMeta.TYPE_INTEGER});
+
+    Object[] row = reader.getRow(rowMeta);
+
+    assertEquals("t_user", row[0]);
+    assertEquals(1000L, row[1]);
+  }
+
+  @Test
+  void testJsonPath_legacyFlatKeyBackwardCompatible() throws Exception {
+    String yaml = """
+                               key1: alpha
+                               key2: 42
+                               """;
+
+    reader.loadString(yaml);
+
+    RowMeta rowMeta =
+        buildRowMeta(
+            new String[] {"field1", "field2"},
+            new String[] {"key1", "key2"},
+            new int[] {IValueMeta.TYPE_STRING, IValueMeta.TYPE_INTEGER});
+
+    Object[] row = reader.getRow(rowMeta);
+
+    assertEquals("alpha", row[0]);
+    assertEquals(42L, row[1]);
+  }
+
+  @Test
+  void testJsonPath_arrayIndex() throws Exception {
+    String yaml = """
+                               tables:
+                                 - name: t_user
+                                 - name: t_order
+                               """;
+
+    reader.loadString(yaml);
+
+    RowMeta rowMeta =
+        buildRowMeta(
+            new String[] {"first_table", "second_table"},
+            new String[] {"$.tables[0].name", "$.tables[1].name"},
+            new int[] {IValueMeta.TYPE_STRING, IValueMeta.TYPE_STRING});
+
+    Object[] row = reader.getRow(rowMeta);
+
+    assertEquals("t_user", row[0]);
+    assertEquals("t_order", row[1]);
+  }
+
+  @Test
+  void testJsonPath_wildcardProducesMultipleRows() throws Exception {
+    String yaml = """
+                               tables:
+                                 - name: t_user
+                                 - name: t_order
+                               """;
+
+    reader.loadString(yaml);
+
+    RowMeta rowMeta =
+        buildRowMeta(
+            new String[] {"name"},
+            new String[] {"$.tables[*].name"},
+            new int[] {IValueMeta.TYPE_STRING});
+
+    Object[] row1 = reader.getRow(rowMeta);
+    Object[] row2 = reader.getRow(rowMeta);
+
+    assertEquals("t_user", row1[0]);
+    assertEquals("t_order", row2[0]);
+  }
+
+  @Test
+  void testGetFieldsAndGetRow_listOfMap() {
+    String yaml = """
+                               - name: Alice
+                                 age: 25
+                               """;
+
+    reader.loadString(yaml);
+
+    RowMeta rowMeta = reader.getFields();
+    assertEquals(List.of("$[*].name", "$[*].age"), 
reader.getDiscoveredPaths());
+
+    Object[] row = reader.getRow(rowMeta);
+
+    assertEquals("Alice", row[0]);
+    assertEquals(25L, row[1]);
+  }
+
+  @Test
+  void testGetDiscoveredPaths_nestedStructure() {
+    String yaml = """
+                               table:
+                                 name: t_user
+                                 startId: 1000
+                               """;
+
+    reader.loadString(yaml);
+
+    assertEquals(List.of("$.table.name", "$.table.startId"), 
reader.getDiscoveredPaths());
+  }
+
+  @Test
+  void testFieldNameFromPath() {
+    assertEquals("name", YamlReader.fieldNameFromPath("$.table.name"));
+    assertEquals("name", YamlReader.fieldNameFromPath("$.tables[0].name"));
+    assertEquals("name", YamlReader.fieldNameFromPath("$.tables[*].name"));
+    assertEquals("name", YamlReader.fieldNameFromPath("$[*].name"));
+    assertEquals("Value", YamlReader.fieldNameFromPath("$[*]"));
+    assertEquals("my field", YamlReader.fieldNameFromPath("$['my 
field'].value"));
+  }
+
+  private RowMeta buildRowMeta(String[] names, String[] paths, int[] types) 
throws Exception {
+    reader.setFieldPaths(paths);
+    RowMeta rowMeta = new RowMeta();
+    for (int i = 0; i < names.length; i++) {
+      rowMeta.addValueMeta(ValueMetaFactory.createValueMeta(names[i], 
types[i]));
+    }
+    return rowMeta;
+  }
+
   @Test
   void testEmptyYaml() {
     reader.loadString("");
@@ -187,15 +331,15 @@ class YamlReaderTests {
   void testGetFields_TypeInference() {
     String yaml =
         """
-                               - intField: 1
-                                 longField: 2
-                                 doubleField: 1.5
-                                 boolField: true
-                                 bigIntField: 99999999999999999999
-                                 bigDecField: 9999999999999999999999999.55
-                                 byteField: 1
-                                 dateField: 2026-03-04T12:03:01
-                               """;
+                                               - intField: 1
+                                                 longField: 2
+                                                 doubleField: 1.5
+                                                 boolField: true
+                                                 bigIntField: 
99999999999999999999
+                                                 bigDecField: 
9999999999999999999999999.55
+                                                 byteField: 1
+                                                 dateField: 2026-03-04T12:03:01
+                                               """;
 
     reader.loadString(yaml);
 

Reply via email to