This is an automated email from the ASF dual-hosted git repository.

tiagobento pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools.git


The following commit(s) were added to refs/heads/main by this push:
     new 8b917008e91 kie-issues#1933: Preliminary changes before the new BPMN 
Editor (#3161)
8b917008e91 is described below

commit 8b917008e91e1d8a6cd745b9d200434591c11ad2
Author: Tiago Bento <[email protected]>
AuthorDate: Thu May 29 19:27:19 2025 -0400

    kie-issues#1933: Preliminary changes before the new BPMN Editor (#3161)
---
 packages/bpmn-marshaller/package.json              |   3 +-
 .../src/drools-extension-metaData.ts               | 165 ++++++++
 packages/bpmn-marshaller/src/drools-extension.ts   | 418 +++++++++++++++++++++
 packages/bpmn-marshaller/src/index.ts              | 120 ++++--
 .../src/schemas/bpmn-2_0/Bpmn20Spec.ts}            |  23 +-
 .../src/schemas/bpmn-2_0/Semantic.xsd              |  53 ++-
 .../src/schemas/drools-1_0/README.txt              |   5 +
 .../src/schemas/drools-1_0/drools.xsd              | 148 ++++++++
 packages/bpmn-marshaller/tests/idempotency.test.ts |   4 +-
 .../bpmn-marshaller/tests/namespacedAttributes.ts  | 113 ++++++
 packages/bpmn-marshaller/tests/typeSafety.test.ts  |   2 +-
 packages/bpmn-marshaller/tests/versions.test.ts    |   2 +-
 .../tests-e2e/__fixtures__/files/can-drive.dmn     |   8 +-
 .../__fixtures__/files/find-employees.dmn          |  70 ++--
 .../__fixtures__/files/loan-pre-qualification.dmn  |  66 ++--
 .../dmn-marshaller/src/schemas/kie-1_0/KIE.xsd     |   2 +-
 packages/dmn-marshaller/tests/xsdSequence.test.ts  |   6 +-
 packages/react-hooks/src/usePreviousRef.ts         |   1 +
 packages/xml-parser-ts-codegen/README.md           |   2 +-
 packages/xml-parser-ts-codegen/src/codegen.ts      | 293 +++++++++++----
 .../ts-gen/meta.ts                                 |  16 +-
 .../ts-gen/types.d.ts                              |  22 +-
 packages/xml-parser-ts-codegen/src/types.d.ts      |  23 +-
 .../src/elementFilter.ts}                          |  22 +-
 packages/xml-parser-ts/src/index.ts                |  71 +++-
 25 files changed, 1417 insertions(+), 241 deletions(-)

diff --git a/packages/bpmn-marshaller/package.json 
b/packages/bpmn-marshaller/package.json
index 7462146eed8..dc1de6d4aa5 100644
--- a/packages/bpmn-marshaller/package.json
+++ b/packages/bpmn-marshaller/package.json
@@ -19,8 +19,9 @@
     "src"
   ],
   "scripts": {
-    "build:codegen": "pnpm build:codegen:bpmn20",
+    "build:codegen": "pnpm build:codegen:bpmn20 && pnpm 
build:codegen:drools10",
     "build:codegen:bpmn20": "xml-parser-ts-codegen 
./src/schemas/bpmn-2_0/BPMN20.xsd definitions",
+    "build:codegen:drools10": "xml-parser-ts-codegen 
./src/schemas/drools-1_0/drools.xsd global",
     "build:dev": "rimraf dist && pnpm build:codegen && tsc -p tsconfig.json",
     "build:prod": "pnpm lint && rimraf dist && pnpm build:codegen && tsc -p 
tsconfig.json && pnpm test",
     "lint": "run-script-if --bool \"$(build-env linters.run)\" --then 
\"kie-tools--eslint ./src\"",
diff --git a/packages/bpmn-marshaller/src/drools-extension-metaData.ts 
b/packages/bpmn-marshaller/src/drools-extension-metaData.ts
new file mode 100644
index 00000000000..c2f84083c1a
--- /dev/null
+++ b/packages/bpmn-marshaller/src/drools-extension-metaData.ts
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+import "./drools-extension";
+import { WithMetaData } from "./schemas/bpmn-2_0/ts-gen/types";
+
+export type Bpmn20KnownMetaDataKey =
+  | "elementname" // Used for any Flow Element.
+  | "customTags" // Used for Process Variables.
+  | "customDescription" // Used for "Process Instance Description" as a global 
property.
+  | "customSLADueDate" // Used for "SLA Due date" as a global property.
+  | "customAbortParent" // Used for "Abort parent" flag on Call Activities.
+  | "customAsync" // Used for "Async" flag on Call Activities.
+  | "customActivationCondition" // Used for "Activation condition" expression 
on Ad-hoc sub-processes.
+  | "customAutoStart" // Used for "Ad-hoc auto-start" flag on Ad-hoc 
sub-processes.
+  | "customScope"; // Used for "Signal Scope" flag on intermediateThrowEvent 
and endEvent Signal nodes
+
+export type Bpmn20ProcessVariableTags =
+  | "internal" // TODO: Tiago --> Used for?
+  | "required" // TODO: Tiago --> Used for?
+  | "readonly" // TODO: Tiago --> Used for?
+  | "input" // TODO: Tiago --> Used for?
+  | "output" // TODO: Tiago --> Used for?
+  | "business_relevant" // TODO: Tiago --> Used for?
+  | "tracked"; // TODO: Tiago --> Used for?
+
+/**
+ * Helps reading drools:metaData entries.
+ *
+ * @param obj The object to extract drools:metaData from. No-op if undefined.
+ * @returns A map containing the metaData entries indexed by their name 
attribute.
+ */
+export function parseBpmn20Drools10MetaData(
+  obj: undefined | { extensionElements?: WithMetaData }
+): Map<Bpmn20KnownMetaDataKey, string> {
+  const metadata = new Map<Bpmn20KnownMetaDataKey, string>();
+
+  for (let i = 0; i < (obj?.extensionElements?.["drools:metaData"] ?? 
[]).length; i++) {
+    const entry = obj!.extensionElements!["drools:metaData"]![i];
+    if (entry["@_name"] !== undefined) {
+      metadata.set(entry["@_name"] as Bpmn20KnownMetaDataKey, 
entry["drools:metaValue"].__$$text);
+    }
+  }
+
+  return metadata;
+}
+
+/**
+ * Helps changing drools:metaData entries.
+ *
+ * @param obj The object to extract drools:metaData from. No-op if undefined.
+ * @param keyOrIndex The drools:metaData entry name or entry index.
+ * @param value The drools:metaData entry value.
+ */
+export function setBpmn20Drools10MetaData(
+  obj: undefined | { extensionElements?: WithMetaData },
+  keyOrIndex: Bpmn20KnownMetaDataKey | number,
+  value: string
+): void {
+  if (obj) {
+    obj.extensionElements ??= { "drools:metaData": [] };
+    obj.extensionElements["drools:metaData"] ??= [];
+  }
+
+  if (typeof keyOrIndex === "number") {
+    if (obj?.extensionElements?.["drools:metaData"]?.[keyOrIndex]) {
+      obj.extensionElements["drools:metaData"][keyOrIndex]["drools:metaValue"] 
= { __$$text: value };
+    } else {
+      // nothing to do.
+    }
+  } else {
+    let updated = false;
+    for (let i = 0; i < (obj?.extensionElements?.["drools:metaData"]?.length 
?? 0); i++) {
+      const entry = obj!.extensionElements!["drools:metaData"]![i]!;
+      if (entry["@_name"] === keyOrIndex) {
+        if (updated) {
+          break;
+        }
+        entry["drools:metaValue"] = { __$$text: value };
+        updated = true;
+      }
+    }
+
+    if (!updated) {
+      obj?.extensionElements?.["drools:metaData"]?.push({
+        "@_name": keyOrIndex,
+        "drools:metaValue": { __$$text: value },
+      });
+    }
+  }
+}
+
+/**
+ * Helps adding drools:metaData entries to objects.
+ *
+ * @param obj The object to extract drools:metaData from. No-op if undefined.
+ * @param key The drools:metaData entry name.
+ * @param value The drools:metaData entry value.
+ */
+export function addBpmn20Drools10MetaData(
+  obj: undefined | { extensionElements?: WithMetaData },
+  key: Bpmn20KnownMetaDataKey,
+  value: string
+): void {
+  if (obj) {
+    obj.extensionElements ??= { "drools:metaData": [] };
+    obj.extensionElements["drools:metaData"] ??= [];
+    obj.extensionElements["drools:metaData"]?.push({
+      "@_name": key,
+      "drools:metaValue": { __$$text: value },
+    });
+  }
+}
+
+/**
+ * Helps renaming drools:metaData entries.
+ *
+ * @param obj The object to extract drools:metaData from. No-op if undefined.
+ * @param index The drools:metaData entry index.
+ * @param newKeyName The new drools:metaData entry name.
+ */
+export function renameBpmn20Drools10MetaDataEntry(
+  obj: undefined | { extensionElements?: WithMetaData },
+  index: number,
+  newKeyName: string
+): void {
+  if (obj?.extensionElements?.["drools:metaData"]?.[index]) {
+    obj.extensionElements["drools:metaData"][index]["@_name"] = newKeyName;
+  }
+}
+
+/**
+ * Helps deleting drools:metaData entries.
+ *
+ * @param obj The object to extract drools:metaData from. No-op if undefined.
+ * @param index The drools:metaData entry name.
+ */
+export function deleteBpmn20Drools10MetaDataEntry(
+  obj: undefined | { extensionElements?: WithMetaData },
+  keyOrIndex: string | number
+): void {
+  if (typeof keyOrIndex === "number") {
+    obj?.extensionElements?.["drools:metaData"]?.splice(keyOrIndex, 1);
+  } else if (obj?.extensionElements?.["drools:metaData"]) {
+    obj.extensionElements!["drools:metaData"] = 
obj.extensionElements["drools:metaData"].filter(
+      (m) => m["@_name"] !== keyOrIndex
+    );
+  }
+}
diff --git a/packages/bpmn-marshaller/src/drools-extension.ts 
b/packages/bpmn-marshaller/src/drools-extension.ts
new file mode 100644
index 00000000000..57fb49c18b2
--- /dev/null
+++ b/packages/bpmn-marshaller/src/drools-extension.ts
@@ -0,0 +1,418 @@
+/*
+ * 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.
+ */
+
+import { Namespaced, mergeMetas } from "@kie-tools/xml-parser-ts";
+
+import { meta as bpmn20meta, ns as bpmn20ns } from 
"./schemas/bpmn-2_0/ts-gen/meta";
+import "./schemas/bpmn-2_0/ts-gen/types";
+
+import { meta as drools10meta, ns as drools10ns } from 
"./schemas/drools-1_0/ts-gen/meta";
+import {
+  drools__GLOBAL__global,
+  drools__GLOBAL__import,
+  drools__GLOBAL__metaData,
+  drools__GLOBAL__onEntry_script,
+  drools__GLOBAL__onExit_script,
+} from "./schemas/drools-1_0/ts-gen/types";
+
+export const DROOLS_NS__PRE_GWT_REMOVAL = "http://www.jboss.org/drools";;
+export const DROOLS_NS = "drools:";
+export type DROOLS = "drools";
+
+export { Namespaced };
+
+export const BUSINESS_RULE_TASK_IMPLEMENTATIONS = {
+  drools: "http://www.jboss.org/drools/rule";,
+  dmn: "http://www.jboss.org/drools/dmn";,
+};
+
+export const 
BUSINESS_RULE_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING = {
+  FILE_PATH: "fileName",
+  NAMESPACE: "namespace",
+  MODEL_NAME: "model",
+};
+
+export const USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING 
= {
+  TASK_NAME: "TaskName",
+  SKIPPABLE: "Skippable",
+  GROUP_ID: "GroupId",
+  COMMENT: "Comment",
+  DESCRIPTION: "Description",
+  PRIORITY: "Priority",
+  CREATED_BY: "CreatedBy",
+  CONTENT: "Content",
+  NOT_STARTED_REASSIGN: "NotStartedReassign",
+  NOT_COMPLETED_REASSIGN: "NotCompletedReassign",
+  NOT_STARTED_NOTIFY: "NotStartedNotify",
+  NOT_COMPLETELY_NOTIFY: "NotCompletedNotify",
+  MULTI_INSTANCE_ITEM_TYPE: "multiInstanceItemType",
+};
+
+export const DATA_INPUT_RESERVED_NAMES = new Set([
+  
BUSINESS_RULE_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.FILE_PATH,
+  
BUSINESS_RULE_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.NAMESPACE,
+  
BUSINESS_RULE_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.MODEL_NAME,
+  USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.TASK_NAME,
+  USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.SKIPPABLE,
+  USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.GROUP_ID,
+  USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.COMMENT,
+  USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.DESCRIPTION,
+  USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.PRIORITY,
+  USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.CREATED_BY,
+  USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.CONTENT,
+  
USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.NOT_STARTED_REASSIGN,
+  
USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.NOT_COMPLETED_REASSIGN,
+  
USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.NOT_STARTED_NOTIFY,
+  
USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.NOT_COMPLETELY_NOTIFY,
+  
USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.MULTI_INSTANCE_ITEM_TYPE,
+]);
+
+export const SERVICE_TASK_IMPLEMENTATIONS = {
+  java: "Java",
+  webService: "WebService",
+};
+
+///////////////////////////
+///       BPMN 2.0      ///
+///////////////////////////
+
+declare module "./schemas/bpmn-2_0/ts-gen/types" {
+  type WithMetaData = {
+    "drools:metaData"?: Namespaced<DROOLS, drools__GLOBAL__metaData>[];
+  };
+
+  export interface BPMN20__tProcess {
+    "@_drools:packageName"?: Namespaced<DROOLS, string>;
+    "@_drools:version"?: Namespaced<DROOLS, string>;
+    "@_drools:adHoc"?: Namespaced<DROOLS, boolean>;
+  }
+
+  export interface BPMN20__tProcess__extensionElements extends WithMetaData, 
WithEntryAndExitScripts {
+    "drools:import"?: Namespaced<DROOLS, drools__GLOBAL__import>[];
+    "drools:global"?: Namespaced<DROOLS, drools__GLOBAL__global>[];
+  }
+
+  type WithEntryAndExitScripts = {
+    "drools:onEntry-script"?: Namespaced<DROOLS, 
drools__GLOBAL__onEntry_script>;
+    "drools:onExit-script"?: Namespaced<DROOLS, drools__GLOBAL__onExit_script>;
+  };
+
+  // *************************************************** NOTE 
******************************************************
+  //
+  //  Some sequenceFlow elements are commented on purpose. They're here for 
completeness, but they're not currently
+  //                   relevant by this BPMN marshaller, since none of those 
are executable.
+  //
+  // 
***************************************************************************************************************
+
+  export interface BPMN20__tAdHocSubProcess__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tBoundaryEvent__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tBusinessRuleTask__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tCallActivity__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  // export interface BPMN20__tCallChoreography__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  // export interface BPMN20__tChoreographyTask__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tComplexGateway__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tDataObject__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  // export interface BPMN20__tDataObjectReference__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  // export interface BPMN20__tDataStoreReference__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tEndEvent__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tEvent__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tEventBasedGateway__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tExclusiveGateway__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  // export interface BPMN20__tImplicitThrowEvent__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tInclusiveGateway__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tIntermediateCatchEvent__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tIntermediateThrowEvent__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  // export interface BPMN20__tManualTask__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tParallelGateway__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  // export interface BPMN20__tReceiveTask__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tScriptTask__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  // export interface BPMN20__tSendTask__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tSequenceFlow__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tServiceTask__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tStartEvent__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  // export interface BPMN20__tSubChoreography__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tSubProcess__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tTask__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tTransaction__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tUserTask__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tAssociation__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tGroup__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+  export interface BPMN20__tTextAnnotation__extensionElements extends 
WithEntryAndExitScripts, WithMetaData {}
+
+  // Other
+  export interface BPMN20__tProperty__extensionElements extends WithMetaData {}
+  export interface BPMN20__tLane__extensionElements extends WithMetaData {}
+
+  // Call activity
+  export interface BPMN20__tCallActivity {
+    "@_drools:independent"?: Namespaced<DROOLS, boolean>;
+    "@_drools:waitForCompletion"?: Namespaced<DROOLS, boolean>;
+  }
+
+  // Service task
+  export interface BPMN20__tServiceTask {
+    "@_drools:serviceimplementation"?: Namespaced<DROOLS, string>;
+    "@_drools:serviceinterface"?: Namespaced<DROOLS, string>;
+    "@_drools:serviceoperation"?: Namespaced<DROOLS, string>;
+  }
+
+  // Business Rule task
+  export interface BPMN20__tBusinessRuleTask {
+    "@_drools:ruleFlowGroup"?: Namespaced<DROOLS, string>;
+  }
+
+  // Data Input
+  export interface BPMN20__tDataInput {
+    "@_drools:dtype"?: Namespaced<DROOLS, string>;
+  }
+
+  // Data Output
+  export interface BPMN20__tDataOutput {
+    "@_drools:dtype"?: Namespaced<DROOLS, string>;
+  }
+
+  // Message Event Definition
+  export interface BPMN20__tMessageEventDefinition {
+    "@_drools:msgref"?: Namespaced<DROOLS, string>;
+  }
+
+  // Escalation Event Definition
+  export interface BPMN20__tEscalationEventDefinition {
+    "@_drools:esccode"?: Namespaced<DROOLS, string>;
+  }
+
+  // Error Event Definition
+  export interface BPMN20__tErrorEventDefinition {
+    "@_drools:erefname"?: Namespaced<DROOLS, string>;
+  }
+
+  // Sequence Flow Definition
+  export interface BPMN20__tSequenceFlow {
+    "@_drools:priority"?: Namespaced<DROOLS, string>;
+  }
+}
+
+bpmn20ns.set(DROOLS_NS, drools10ns.get("")!);
+bpmn20ns.set(drools10ns.get("")!, DROOLS_NS);
+
+mergeMetas(bpmn20meta, [[DROOLS_NS, drools10meta]]);
+
+// Process attrs
+(bpmn20meta["BPMN20__tProcess"] as any)["@_drools:packageName"] = {
+  type: "string",
+  isArray: false,
+  xsdType: "xsd:string",
+  fromType: "BPMN20__tProcess",
+};
+(bpmn20meta["BPMN20__tProcess"] as any)["@_drools:version"] = {
+  type: "string",
+  isArray: false,
+  xsdType: "xsd:string",
+  fromType: "BPMN20__tProcess",
+};
+(bpmn20meta["BPMN20__tProcess"] as any)["@_drools:adHoc"] = {
+  type: "boolean",
+  isArray: false,
+  xsdType: "xsd:boolean",
+  fromType: "BPMN20__tProcess",
+};
+
+// Process elements
+(bpmn20meta["BPMN20__tProcess__extensionElements"] as any)["drools:import"] = {
+  type: "drools__GLOBAL__import",
+  isArray: true,
+  xsdType: "// local type",
+  fromType: "BPMN20__tProcess__extensionElements",
+};
+(bpmn20meta["BPMN20__tProcess__extensionElements"] as any)["drools:global"] = {
+  type: "drools__GLOBAL__global",
+  isArray: true,
+  xsdType: "// local type",
+  fromType: "BPMN20__tProcess__extensionElements",
+};
+
+// Business Rule Task attrs
+(bpmn20meta["BPMN20__tBusinessRuleTask"] as any)["@_drools:ruleFlowGroup"] = {
+  type: "string",
+  isArray: false,
+  xsdType: "xsd:string",
+  fromType: "BPMN20__tBusinessRuleTask",
+};
+
+// Call Activity attrs
+(bpmn20meta["BPMN20__tCallActivity"] as any)["@_drools:independent"] = {
+  type: "boolean",
+  isArray: false,
+  xsdType: "xsd:boolean",
+  fromType: "BPMN20__tCallActivity",
+};
+(bpmn20meta["BPMN20__tCallActivity"] as any)["@_drools:waitForCompletion"] = {
+  type: "boolean",
+  isArray: false,
+  xsdType: "xsd:boolean",
+  fromType: "BPMN20__tCallActivity",
+};
+
+// Service Task attrs
+(bpmn20meta["BPMN20__tServiceTask"] as any)["@_drools:serviceimplementation"] 
= {
+  type: "string",
+  isArray: false,
+  xsdType: "xsd:string",
+  fromType: "BPMN20__tServiceTask",
+};
+(bpmn20meta["BPMN20__tServiceTask"] as any)["@_drools:serviceinterface"] = {
+  type: "string",
+  isArray: false,
+  xsdType: "xsd:string",
+  fromType: "BPMN20__tServiceTask",
+};
+(bpmn20meta["BPMN20__tServiceTask"] as any)["@_drools:serviceoperation"] = {
+  type: "string",
+  isArray: false,
+  xsdType: "xsd:string",
+  fromType: "BPMN20__tServiceTask",
+};
+
+// Data Input
+(bpmn20meta["BPMN20__tDataInput"] as any)["@_drools:dtype"] = {
+  type: "string",
+  isArray: false,
+  xsdType: "xsd:string",
+  fromType: "BPMN20__tDataInput",
+};
+// Data Output
+(bpmn20meta["BPMN20__tDataOutput"] as any)["@_drools:dtype"] = {
+  type: "string",
+  isArray: false,
+  xsdType: "xsd:string",
+  fromType: "BPMN20__tDataOutput",
+};
+
+// Message Event Definition
+(bpmn20meta["BPMN20__tMessageEventDefinition"] as any)["@_drools:msgref"] = {
+  type: "string",
+  isArray: false,
+  xsdType: "xsd:string",
+  fromType: "BPMN20__tMessageEventDefinition",
+};
+
+// Escalation Event Definition
+(bpmn20meta["BPMN20__tEscalationEventDefinition"] as any)["@_drools:esccode"] 
= {
+  type: "string",
+  isArray: false,
+  xsdType: "xsd:string",
+  fromType: "BPMN20__tEscalationEventDefinition",
+};
+
+// Error Event Definition
+(bpmn20meta["BPMN20__tErrorEventDefinition"] as any)["@_drools:erefname"] = {
+  type: "string",
+  isArray: false,
+  xsdType: "xsd:string",
+  fromType: "BPMN20__tErrorEventDefinition",
+};
+
+// Error Event Definition
+(bpmn20meta["BPMN20__tSequenceFlow"] as any)["@_drools:priority"] = {
+  type: "string",
+  isArray: false,
+  xsdType: "xsd:string",
+  fromType: "BPMN20__tSequenceFlow",
+};
+
+class MetaType {
+  public static of(typeName: keyof typeof bpmn20meta) {
+    return new MetaType(typeName);
+  }
+
+  private constructor(private readonly typeName: keyof typeof bpmn20meta) {}
+
+  public hasMetadata() {
+    (bpmn20meta[this.typeName] as any)["drools:metaData"] = {
+      type: "drools__GLOBAL__metaData",
+      isArray: true,
+      xsdType: "// local type",
+      fromType: this.typeName,
+    };
+    return this;
+  }
+
+  public hasEntryAndExitScripts() {
+    (bpmn20meta[this.typeName] as any)["drools:onEntry-script"] = {
+      type: "drools__GLOBAL__onEntry_script",
+      isArray: false,
+      xsdType: "// local type",
+      fromType: this.typeName,
+    };
+    (bpmn20meta[this.typeName] as any)["drools:onExit-script"] = {
+      type: "drools__GLOBAL__onExit_script",
+      isArray: false,
+      xsdType: "// local type",
+      fromType: this.typeName,
+    };
+    return this;
+  }
+}
+
+//
+// See some of those are commented above too.
+//
+MetaType.of("BPMN20__tAdHocSubProcess__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tBoundaryEvent__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tBusinessRuleTask__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tCallActivity__extensionElements").hasEntryAndExitScripts().hasMetadata();
+// 
MetaType.of("BPMN20__tCallChoreography__extensionElements").hasEntryAndExitScripts().hasMetadata();
+// 
MetaType.of("BPMN20__tChoreographyTask__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tComplexGateway__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tDataObject__extensionElements").hasEntryAndExitScripts().hasMetadata();
+// 
MetaType.of("BPMN20__tDataObjectReference__extensionElements").hasEntryAndExitScripts().hasMetadata();
+// 
MetaType.of("BPMN20__tDataStoreReference__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tEndEvent__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tEvent__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tEventBasedGateway__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tExclusiveGateway__extensionElements").hasEntryAndExitScripts().hasMetadata();
+// 
MetaType.of("BPMN20__tImplicitThrowEvent__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tInclusiveGateway__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tIntermediateCatchEvent__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tIntermediateThrowEvent__extensionElements").hasEntryAndExitScripts().hasMetadata();
+// 
MetaType.of("BPMN20__tManualTask__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tParallelGateway__extensionElements").hasEntryAndExitScripts().hasMetadata();
+// 
MetaType.of("BPMN20__tReceiveTask__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tScriptTask__extensionElements").hasEntryAndExitScripts().hasMetadata();
+// 
MetaType.of("BPMN20__tSendTask__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tSequenceFlow__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tServiceTask__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tStartEvent__extensionElements").hasEntryAndExitScripts().hasMetadata();
+// 
MetaType.of("BPMN20__tSubChoreography__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tSubProcess__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tTask__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tTransaction__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tUserTask__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tAssociation__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tGroup__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tTextAnnotation__extensionElements").hasEntryAndExitScripts().hasMetadata();
+
+// Process
+MetaType.of("BPMN20__tProcess__extensionElements").hasMetadata();
+
+// Property
+MetaType.of("BPMN20__tProperty__extensionElements").hasMetadata();
+
+// Lane
+MetaType.of("BPMN20__tLane__extensionElements").hasMetadata();
diff --git a/packages/bpmn-marshaller/src/index.ts 
b/packages/bpmn-marshaller/src/index.ts
index 434642fda7f..df373603d2b 100644
--- a/packages/bpmn-marshaller/src/index.ts
+++ b/packages/bpmn-marshaller/src/index.ts
@@ -17,46 +17,122 @@
  * under the License.
  */
 
-import { Meta, getInstanceNs, domParser, getParser } from 
"@kie-tools/xml-parser-ts";
+import { Meta, XmlParserTs, domParser, getInstanceNs, getParser } from 
"@kie-tools/xml-parser-ts";
 import {
-  meta as bpmn20meta,
-  elements as bpmn20elements,
   subs as bpmn20subs,
+  elements as bpmn20elements,
+  meta as bpmn20meta,
   root as bpmn20root,
   ns as bpmn20ns,
 } from "./schemas/bpmn-2_0/ts-gen/meta";
-
 import { BPMN20__tDefinitions } from "./schemas/bpmn-2_0/ts-gen/types";
 
-type BpmnDefinitions = { definitions: BPMN20__tDefinitions };
+export type BpmnMarshaller<V extends BpmnMarshallerVersions = "latest"> = 
InternalBpmnMarshaller<V> & {
+  originalVersion: BpmnVersions;
+  isLatest: boolean;
+};
+
+export type InternalBpmnMarshaller<V extends BpmnMarshallerVersions = 
"latest"> = V extends "2.0"
+  ? BpmnMarshaller20
+  : V extends "latest"
+    ? BpmnLatestMarshaller
+    : never;
 
-type BpmnMarshaller = {
-  parser: { parse(): BpmnDefinitions };
-  builder: { build(json: BpmnDefinitions): string };
+export type BpmnMarshallerBase = {
   instanceNs: Map<string, string>;
   root: { element: string; type: string };
   meta: Meta;
-  version: "2.0";
 };
 
-export function getMarshaller(xml: string): BpmnMarshaller {
-  const domdoc = domParser.getDomDocument(xml);
-  const instanceNs = getInstanceNs(domdoc);
+export type AllBpmnMarshallers = BpmnMarshaller20;
+
+export type KieExtensionVersions = "0.0" | "1.0";
+export type BpmnVersions = AllBpmnMarshallers["version"];
+export type BpmnMarshallerVersions = AllBpmnMarshallers["version"] | "latest";
+
+export type BpmnMarshaller20 = BpmnMarshallerBase & {
+  parser: { parse(): { definitions: BPMN20__tDefinitions } };
+  builder: { build(json: { definitions: BPMN20__tDefinitions }): string };
+  version: "2.0";
+};
 
-  const p = getParser<BpmnDefinitions>({
+export const BPMN_PARSERS: Record<BpmnVersions, XmlParserTs<any>> = {
+  "2.0": getParser<{ [bpmn20root.element]: BPMN20__tDefinitions }>({
     ns: bpmn20ns,
     meta: bpmn20meta,
     subs: bpmn20subs,
     elements: bpmn20elements,
     root: bpmn20root,
-  });
+  }),
+};
 
-  return {
-    instanceNs,
-    version: "2.0",
-    root: bpmn20root,
-    meta: bpmn20meta,
-    parser: { parse: () => p.parse({ type: "domdoc", domdoc, instanceNs 
}).json },
-    builder: { build: (json: BpmnDefinitions) => p.build({ json, instanceNs }) 
},
-  };
+export const BPMN_VERSIONS_TIMELINE: BpmnVersions[] = ["2.0"];
+export const BPMN_LATEST_VERSION = "2.0" as const;
+export type BpmnLatestMarshaller = BpmnMarshaller20;
+export type BpmnLatestModel = { [bpmn20root.element]: BPMN20__tDefinitions };
+
+export type BpmnMarshallerOpts<V extends BpmnMarshallerVersions> = { 
upgradeTo?: V };
+
+export function getMarshaller<V extends BpmnMarshallerVersions>(
+  xml: string,
+  opts?: BpmnMarshallerOpts<V>
+): BpmnMarshaller<V> {
+  const originalDomdoc = domParser.getDomDocument(xml);
+  const originalInstanceNs = getInstanceNs(originalDomdoc);
+
+  const originalMarshaller = getMarshallerForFixedVersion(originalDomdoc, 
originalInstanceNs);
+
+  // `opts.upgradeTo` is optional. It defaults to not upgrading at all. 
"latest" is an alias to whatever the `BPMN_LATEST_VERSION` constante declares.
+  const targetVersion: BpmnVersions =
+    opts?.upgradeTo === "latest" ? BPMN_LATEST_VERSION : opts?.upgradeTo ?? 
originalMarshaller.version;
+
+  // If the XML is already on the latest version, we don't do anything else 
and just return the marshaller.
+  if (originalMarshaller.version === targetVersion) {
+    return {
+      ...(originalMarshaller as InternalBpmnMarshaller<V>),
+      originalVersion: originalMarshaller.version,
+      isLatest: true,
+    };
+  } else {
+    throw new Error(
+      `BPMN MARSHALLER: Cannot build BPMN ${targetVersion} marshaller from a 
model that's already in version '${originalMarshaller.version}'. Downgrading 
BPMN models is not possible.`
+    );
+  }
+}
+
+export function getBpmnVersion(instanceNs: Map<string, string>): BpmnVersions {
+  // Do not remove this '!== undefined', as "" is a valid namespace on the 
instanceNs map, although it is a falsy value.
+  if (instanceNs.get(bpmn20ns.get("")!) !== undefined) {
+    return "2.0";
+  }
+  // None.. throw error
+  else {
+    throw new Error(
+      `BPMN MARSHALLER: Unknown version declared for BPMN. Instance NS --> 
'${JSON.stringify([
+        ...instanceNs.entries(),
+      ])}'.`
+    );
+  }
+}
+
+export function getMarshallerForFixedVersion(domdoc: Document, instanceNs: 
Map<string, string>): AllBpmnMarshallers {
+  const version = getBpmnVersion(instanceNs);
+
+  switch (version) {
+    case "2.0":
+      return {
+        instanceNs,
+        version: "2.0",
+        root: bpmn20root,
+        meta: bpmn20meta,
+        parser: { parse: () => BPMN_PARSERS["2.0"].parse({ type: "domdoc", 
domdoc, instanceNs }).json },
+        builder: { build: (json) => BPMN_PARSERS["2.0"].build({ json, 
instanceNs }) },
+      };
+    default:
+      throw new Error(
+        `BPMN MARSHALLER: Unknown version declared for BPMN. Instance NS --> 
'${JSON.stringify([
+          ...instanceNs.entries(),
+        ])}'.`
+      );
+  }
 }
diff --git a/packages/react-hooks/src/usePreviousRef.ts 
b/packages/bpmn-marshaller/src/schemas/bpmn-2_0/Bpmn20Spec.ts
similarity index 56%
copy from packages/react-hooks/src/usePreviousRef.ts
copy to packages/bpmn-marshaller/src/schemas/bpmn-2_0/Bpmn20Spec.ts
index b5855874e6a..995efdfeb55 100644
--- a/packages/react-hooks/src/usePreviousRef.ts
+++ b/packages/bpmn-marshaller/src/schemas/bpmn-2_0/Bpmn20Spec.ts
@@ -17,16 +17,19 @@
  * under the License.
  */
 
-import { useEffect, useRef } from "react";
+import { ns as bpmn20ns } from "../bpmn-2_0/ts-gen/meta";
 
-export function usePreviousRef<T>(value: T): React.MutableRefObject<T> {
-  const ref = useRef<T>(value);
+export type UniqueNameIndex = Map<string, string>;
 
-  useEffect(() => {
-    if (ref.current !== value) {
-      ref.current = value;
-    }
-  }, [value]);
+export const BPMN20_SPEC = {
+  isValidName: (id: string, name: string | undefined, allUniqueNames: 
UniqueNameIndex): boolean => {
+    return true; // FIXME: Tiago: Implement (valid name)
+  },
+};
 
-  return ref;
-}
+export const allBpmnImportNamespaces = new Set([bpmn20ns.get("")!]);
+
+export const KIE_BPMN_UNKNOWN_NAMESPACE = 
"https://kie.apache.org/bpmn/unknown";;
+
+export const BOUNDARY_EVENT_CANCEL_ACTIVITY_DEFAULT_VALUE = true;
+export const 
START_EVENT_NODE_ON_EVENT_SUB_PROCESSES_IS_INTERRUPTING_DEFAULT_VALUE = true;
diff --git a/packages/bpmn-marshaller/src/schemas/bpmn-2_0/Semantic.xsd 
b/packages/bpmn-marshaller/src/schemas/bpmn-2_0/Semantic.xsd
index 83ffee85c33..71850dec2cd 100644
--- a/packages/bpmn-marshaller/src/schemas/bpmn-2_0/Semantic.xsd
+++ b/packages/bpmn-marshaller/src/schemas/bpmn-2_0/Semantic.xsd
@@ -58,8 +58,14 @@
     <xsd:complexContent>
       <xsd:extension base="tBaseElement">
         <xsd:sequence>
-          <xsd:element name="from" type="tExpression" minOccurs="1" 
maxOccurs="1" />
-          <xsd:element name="to" type="tExpression" minOccurs="1" 
maxOccurs="1" />
+          <xsd:element name="from" type="tFormalExpression" minOccurs="1" 
maxOccurs="1" />
+          <xsd:element name="to" type="tFormalExpression" minOccurs="1" 
maxOccurs="1" />
+          <xsd:element name="inputName" type="xsd:string" minOccurs="0" 
maxOccurs="unbounded" />
+          <xsd:element name="inputDataType" type="xsd:string" minOccurs="0" 
maxOccurs="unbounded" />
+          <xsd:element name="inputSource" type="xsd:string" minOccurs="0" 
maxOccurs="unbounded" />
+          <xsd:element name="outputName" type="xsd:string" minOccurs="0" 
maxOccurs="unbounded" />
+          <xsd:element name="outputDataType" type="xsd:string" minOccurs="0" 
maxOccurs="unbounded" />
+          <xsd:element name="outputTarget" type="xsd:string" minOccurs="0" 
maxOccurs="unbounded" />
         </xsd:sequence>
       </xsd:extension>
     </xsd:complexContent>
@@ -95,7 +101,15 @@
   <xsd:complexType name="tBaseElement" abstract="true">
     <xsd:sequence>
       <xsd:element ref="documentation" minOccurs="0" maxOccurs="unbounded" />
-      <xsd:element ref="extensionElements" minOccurs="0" maxOccurs="1" />
+      <!-- (begin) Manually edited. Inlined `tExtensionElements` for type-safe 
extensibility. -->
+      <xsd:element name="extensionElements" minOccurs="0" maxOccurs="1">
+        <xsd:complexType>
+          <xsd:sequence>
+            <xsd:any namespace="##other" processContents="lax" minOccurs="0" 
maxOccurs="unbounded" />
+          </xsd:sequence>
+        </xsd:complexType>
+      </xsd:element>
+      <!-- (end) -->
     </xsd:sequence>
     <xsd:attribute name="id" type="xsd:ID" use="optional" />
     <xsd:anyAttribute namespace="##other" processContents="lax" />
@@ -105,7 +119,15 @@
   <xsd:complexType name="tBaseElementWithMixedContent" abstract="true" 
mixed="true">
     <xsd:sequence>
       <xsd:element ref="documentation" minOccurs="0" maxOccurs="unbounded" />
-      <xsd:element ref="extensionElements" minOccurs="0" maxOccurs="1" />
+      <!-- (begin) Manually edited. Inlined `tExtensionElements` for type-safe 
extensibility. -->
+      <xsd:element name="extensionElements" minOccurs="0" maxOccurs="1">
+        <xsd:complexType>
+          <xsd:sequence>
+            <xsd:any namespace="##other" processContents="lax" minOccurs="0" 
maxOccurs="unbounded" />
+          </xsd:sequence>
+        </xsd:complexType>
+      </xsd:element>
+      <!-- (end) -->
     </xsd:sequence>
     <xsd:attribute name="id" type="xsd:ID" use="optional" />
     <xsd:anyAttribute namespace="##other" processContents="lax" />
@@ -177,13 +199,6 @@
     </xsd:complexContent>
   </xsd:complexType>
 
-  <xsd:element name="cancelEventDefinition" type="tCancelEventDefinition" 
substitutionGroup="eventDefinition" />
-  <xsd:complexType name="tCancelEventDefinition">
-    <xsd:complexContent>
-      <xsd:extension base="tEventDefinition" />
-    </xsd:complexContent>
-  </xsd:complexType>
-
   <xsd:element name="catchEvent" type="tCatchEvent" />
   <xsd:complexType name="tCatchEvent" abstract="true">
     <xsd:complexContent>
@@ -682,12 +697,13 @@
     <xsd:attribute name="mustUnderstand" type="xsd:boolean" use="optional" 
default="false" />
   </xsd:complexType>
 
-  <xsd:element name="extensionElements" type="tExtensionElements" />
+  <!-- Manually edited. This is inlined in baseElement and 
baseElementWithMixedContent, for type-safe extensibility. -->
+  <!-- <xsd:element name="extensionElements" type="tExtensionElements" />
   <xsd:complexType name="tExtensionElements">
     <xsd:sequence>
       <xsd:any namespace="##other" processContents="lax" minOccurs="0" 
maxOccurs="unbounded" />
     </xsd:sequence>
-  </xsd:complexType>
+  </xsd:complexType> -->
 
   <xsd:element name="flowElement" type="tFlowElement" />
   <xsd:complexType name="tFlowElement" abstract="true">
@@ -802,8 +818,14 @@
     <xsd:complexContent>
       <xsd:extension base="tGlobalTask">
         <xsd:sequence>
+          <xsd:element name="taskName" type="xsd:string" minOccurs="0" 
maxOccurs="1" />
+          <xsd:element name="subject" type="xsd:string" minOccurs="0" 
maxOccurs="1" />
+          <xsd:element name="content" type="xsd:string" minOccurs="0" 
maxOccurs="1" />
+          <xsd:element name="priority" type="xsd:string" minOccurs="0" 
maxOccurs="1" />
           <xsd:element ref="rendering" minOccurs="0" maxOccurs="unbounded" />
         </xsd:sequence>
+        <xsd:attribute name="description" type="xsd:string" use="optional" />
+        <xsd:attribute name="skippable" type="xsd:boolean" default="false" />
         <xsd:attribute name="implementation" type="tImplementation" 
default="##unspecified" />
       </xsd:extension>
     </xsd:complexContent>
@@ -1498,19 +1520,22 @@
     <xsd:complexContent>
       <xsd:extension base="tArtifact">
         <xsd:sequence>
-          <xsd:element ref="text" minOccurs="0" maxOccurs="1" />
+          <xsd:element name="text" type="xsd:string" minOccurs="0" 
maxOccurs="1" />
         </xsd:sequence>
         <xsd:attribute name="textFormat" type="xsd:string" 
default="text/plain" />
       </xsd:extension>
     </xsd:complexContent>
   </xsd:complexType>
 
+  <!-- Manually edited to make this type-safe -->
+  <!-- 
   <xsd:element name="text" type="tText" />
   <xsd:complexType name="tText" mixed="true">
     <xsd:sequence>
       <xsd:any namespace="##any" processContents="lax" minOccurs="0" />
     </xsd:sequence>
   </xsd:complexType>
+  -->
 
   <xsd:element name="throwEvent" type="tThrowEvent" />
   <xsd:complexType name="tThrowEvent" abstract="true">
diff --git a/packages/bpmn-marshaller/src/schemas/drools-1_0/README.txt 
b/packages/bpmn-marshaller/src/schemas/drools-1_0/README.txt
new file mode 100644
index 00000000000..0467ea8cada
--- /dev/null
+++ b/packages/bpmn-marshaller/src/schemas/drools-1_0/README.txt
@@ -0,0 +1,5 @@
+This extension for BPMN 2.0 has been in place since before migrating to Apache 
KIE, back when KIE was managed by Red Hat.
+
+To ensure retro-compatibility, this is being kept as is.
+
+In the future we can migrate to a "KIE" extension, instead of "Drools".
diff --git a/packages/bpmn-marshaller/src/schemas/drools-1_0/drools.xsd 
b/packages/bpmn-marshaller/src/schemas/drools-1_0/drools.xsd
new file mode 100644
index 00000000000..941be9e96a4
--- /dev/null
+++ b/packages/bpmn-marshaller/src/schemas/drools-1_0/drools.xsd
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ 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.
+  -->
+<xsd:schema
+  xmlns:xsd="http://www.w3.org/2001/XMLSchema";
+  xmlns:drools="http://www.jboss.org/drools";
+  targetNamespace="http://www.jboss.org/drools";
+  elementFormDefault="qualified"
+>
+  <xsd:attribute name="packageName">
+    <xsd:simpleType>
+      <xsd:restriction base="xsd:string" />
+    </xsd:simpleType>
+  </xsd:attribute>
+
+  <xsd:attribute name="version">
+    <xsd:simpleType>
+      <xsd:restriction base="xsd:string" />
+    </xsd:simpleType>
+  </xsd:attribute>
+
+  <xsd:attribute name="ruleFlowGroup">
+    <xsd:simpleType>
+      <xsd:restriction base="xsd:string" />
+    </xsd:simpleType>
+  </xsd:attribute>
+
+  <xsd:attribute name="taskName">
+    <xsd:simpleType>
+      <xsd:restriction base="xsd:string" />
+    </xsd:simpleType>
+  </xsd:attribute>
+
+  <xsd:attribute name="priority">
+    <xsd:simpleType>
+      <xsd:restriction base="xsd:integer">
+        <xsd:minInclusive value="1" />
+      </xsd:restriction>
+    </xsd:simpleType>
+  </xsd:attribute>
+
+  <xsd:attribute name="msgref">
+    <xsd:simpleType>
+      <xsd:restriction base="xsd:string" />
+    </xsd:simpleType>
+  </xsd:attribute>
+
+  <xsd:attribute name="esccode">
+    <xsd:simpleType>
+      <xsd:restriction base="xsd:string" />
+    </xsd:simpleType>
+  </xsd:attribute>
+
+  <xsd:attribute name="erefname">
+    <xsd:simpleType>
+      <xsd:restriction base="xsd:string" />
+    </xsd:simpleType>
+  </xsd:attribute>
+
+  <xsd:attributeGroup name="onxscriptattributes">
+    <xsd:attribute name="scriptFormat" type="xsd:string" use="required" />
+  </xsd:attributeGroup>
+
+  <xsd:attributeGroup name="importattributes">
+    <xsd:attribute name="name" type="xsd:string" use="required" />
+  </xsd:attributeGroup>
+
+  <xsd:attributeGroup name="globalattributes">
+    <xsd:attribute name="identifier" type="xsd:string" use="required" />
+    <xsd:attribute name="type" type="xsd:string" use="required" />
+  </xsd:attributeGroup>
+
+  <xsd:element name="onEntry-script">
+    <xsd:complexType>
+      <xsd:sequence>
+        <xsd:element name="script" minOccurs="1" maxOccurs="1" 
type="xsd:string" />
+      </xsd:sequence>
+      <xsd:attributeGroup ref="drools:onxscriptattributes" />
+    </xsd:complexType>
+  </xsd:element>
+
+  <xsd:element name="onExit-script">
+    <xsd:complexType>
+      <xsd:sequence>
+        <xsd:element name="script" minOccurs="1" maxOccurs="1" 
type="xsd:string" />
+      </xsd:sequence>
+      <xsd:attributeGroup ref="drools:onxscriptattributes" />
+    </xsd:complexType>
+  </xsd:element>
+
+  <xsd:element name="import">
+    <xsd:complexType>
+      <xsd:attributeGroup ref="drools:importattributes" />
+    </xsd:complexType>
+  </xsd:element>
+
+  <xsd:element name="global">
+    <xsd:complexType>
+      <xsd:attributeGroup ref="drools:globalattributes" />
+    </xsd:complexType>
+  </xsd:element>
+
+  <!-- Manually written to reflect what's actually happening on BPMN Editor 
(classic) -->
+  <xsd:element name="metaData">
+    <xsd:complexType>
+      <xsd:sequence>
+        <xsd:element name="metaValue" minOccurs="1" maxOccurs="1" 
type="xsd:string" />
+      </xsd:sequence>
+      <xsd:attribute name="name" type="xsd:string" use="required" />
+    </xsd:complexType>
+  </xsd:element>
+
+  <!-- Manually edited to reflect what's actually happening on BPMN Editor 
(classic) -->
+  <!--
+  <xsd:element name="metadata">
+    <xsd:complexType>
+      <xsd:sequence>
+        <xsd:element maxOccurs="unbounded" ref="drools:metaentry" />
+      </xsd:sequence>
+    </xsd:complexType>
+  </xsd:element>
+
+  <xsd:element name="metaentry">
+    <xsd:complexType>
+      <xsd:sequence>
+        <xsd:element name="name" type="xsd:string" minOccurs="1" maxOccurs="1" 
/>
+        <xsd:element name="value" type="xsd:string" minOccurs="1" 
maxOccurs="1" />
+      </xsd:sequence>
+    </xsd:complexType>
+  </xsd:element>
+  -->
+</xsd:schema>
diff --git a/packages/bpmn-marshaller/tests/idempotency.test.ts 
b/packages/bpmn-marshaller/tests/idempotency.test.ts
index 8b08bec2e0d..6156f8baeae 100644
--- a/packages/bpmn-marshaller/tests/idempotency.test.ts
+++ b/packages/bpmn-marshaller/tests/idempotency.test.ts
@@ -28,11 +28,11 @@ describe("idempotency", () => {
     test(path.basename(file), () => {
       const xml_original = fs.readFileSync(path.join(__dirname, file), 
"utf-8");
 
-      const { parser, builder } = getMarshaller(xml_original);
+      const { parser, builder } = getMarshaller(xml_original, { upgradeTo: 
"latest" });
       const json = parser.parse();
 
       const xml_firstPass = builder.build(json);
-      const xml_secondPass = 
builder.build(getMarshaller(xml_firstPass).parser.parse());
+      const xml_secondPass = builder.build(getMarshaller(xml_firstPass, { 
upgradeTo: "latest" }).parser.parse());
 
       expect(xml_firstPass).toStrictEqual(xml_secondPass);
     });
diff --git a/packages/bpmn-marshaller/tests/namespacedAttributes.ts 
b/packages/bpmn-marshaller/tests/namespacedAttributes.ts
new file mode 100644
index 00000000000..465b806941e
--- /dev/null
+++ b/packages/bpmn-marshaller/tests/namespacedAttributes.ts
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+import { getMarshaller } from "@kie-tools/bpmn-marshaller";
+import { DROOLS_NS__PRE_GWT_REMOVAL } from 
"@kie-tools/bpmn-marshaller/dist/drools-extension";
+import { BPMN20__tProcess } from "../dist/schemas/bpmn-2_0/ts-gen/types";
+import "@kie-tools/bpmn-marshaller/dist/drools-extension";
+
+const defaultXmlns = `targetNamespace=""
+  xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL";
+  xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI";
+  xmlns:dc="http://www.omg.org/spec/DD/20100524/DC";
+  xmlns:di="http://www.omg.org/spec/DD/20100524/DI"`;
+
+// Baseline case, happy path.
+describe("namespaced attributes from drools.xsd extension", () => {
+  test("normal", () => {
+    const normal = `<?xml version="1.0" encoding="UTF-8" ?>
+<bpmn2:definitions
+  ${defaultXmlns}
+  xmlns:drools="http://www.jboss.org/drools";
+>
+  <bpmn2:process drools:version="1.0.0" />
+</bpmn2:definitions>`;
+
+    const marshaller = getMarshaller(normal, { upgradeTo: "latest" });
+    const json = marshaller.parser.parse();
+    
expect(json.definitions.rootElement?.[0].__$$element).toStrictEqual("process");
+    expect((json.definitions.rootElement?.[0] as 
BPMN20__tProcess)["@_drools:version"]).toStrictEqual("1.0.0");
+    
expect(poorlyFormatted(marshaller.builder.build(json))).toStrictEqual(poorlyFormatted(normal));
+  });
+
+  // Maps the `drools` namespace as the default.
+  // Since attributes are unnamespaced by default, having a default namespace 
mapped doesn't mean unqualified attributes will all be
+  // assigned to the default namespace.
+  test("defaultNs", () => {
+    const defaultNs = `<?xml version="1.0" encoding="UTF-8" ?>
+<bpmn2:definitions
+  ${defaultXmlns}
+  xmlns="http://www.jboss.org/drools";
+>
+  <bpmn2:process version="1.0.0" />
+</bpmn2:definitions>`;
+
+    const marshaller = getMarshaller(defaultNs, { upgradeTo: "latest" });
+    const json = marshaller.parser.parse();
+    
expect(json.definitions.rootElement?.[0].__$$element).toStrictEqual("process");
+    
expect(json.definitions["@_xmlns"]).toStrictEqual(DROOLS_NS__PRE_GWT_REMOVAL);
+    expect(json.definitions["@_xmlns:drools"]).toStrictEqual(undefined);
+    expect((json.definitions.rootElement?.[0] as 
BPMN20__tProcess)["@_drools:version"]).toStrictEqual(undefined);
+    expect((json.definitions.rootElement?.[0] as 
any)["@_version"]).toStrictEqual("1.0.0");
+    
expect(poorlyFormatted(marshaller.builder.build(json))).toStrictEqual(poorlyFormatted(defaultNs));
+  });
+
+  // Uses a different declaration name for the `drools` namespace.
+  test("renamed", () => {
+    const renamed = `<?xml version="1.0" encoding="UTF-8" ?>
+<bpmn2:definitions
+  ${defaultXmlns}
+  xmlns:droolz="http://www.jboss.org/drools";
+>
+  <bpmn2:process droolz:version="1.0.0" />
+</bpmn2:definitions>`;
+
+    const marshaller = getMarshaller(renamed, { upgradeTo: "latest" });
+    const json = marshaller.parser.parse();
+    
expect(json.definitions.rootElement?.[0].__$$element).toStrictEqual("process");
+    expect((json.definitions.rootElement?.[0] as 
BPMN20__tProcess)["@_drools:version"]).toStrictEqual("1.0.0");
+    expect((json.definitions.rootElement?.[0] as 
any)["@_droolz:version"]).toStrictEqual(undefined);
+    
expect(poorlyFormatted(marshaller.builder.build(json))).toStrictEqual(poorlyFormatted(renamed));
+  });
+
+  // Uses a generic attribute called "version", not tied to the `drools` 
namespace.
+  test("wrong", () => {
+    const wrong = `<?xml version="1.0" encoding="UTF-8" ?>
+<bpmn2:definitions
+  ${defaultXmlns}
+  xmlns:drools="http://www.jboss.org/drools";
+>
+  <bpmn2:process version="1.0.0" />
+</bpmn2:definitions>`;
+
+    const marshaller = getMarshaller(wrong, { upgradeTo: "latest" });
+    const json = marshaller.parser.parse();
+    
expect(json.definitions.rootElement?.[0].__$$element).toStrictEqual("process");
+    expect((json.definitions.rootElement?.[0] as 
BPMN20__tProcess)["@_drools:version"]).not.toStrictEqual("1.0.0");
+    expect((json.definitions.rootElement?.[0] as 
any)["@_version"]).toStrictEqual("1.0.0");
+    
expect(poorlyFormatted(marshaller.builder.build(json))).toStrictEqual(poorlyFormatted(wrong));
+  });
+});
+
+// Just enough for these tests.
+function poorlyFormatted(s: string) {
+  return s
+    .replace(/\n+/g, "") // remove new lines
+    .replace(/  /g, " "); // replace double spaces by single space
+}
diff --git a/packages/bpmn-marshaller/tests/typeSafety.test.ts 
b/packages/bpmn-marshaller/tests/typeSafety.test.ts
index d5cec6a5a68..8e1c212eba4 100644
--- a/packages/bpmn-marshaller/tests/typeSafety.test.ts
+++ b/packages/bpmn-marshaller/tests/typeSafety.test.ts
@@ -45,7 +45,7 @@ describe("type safety", () => {
     test(path.basename(file), () => {
       const xml = fs.readFileSync(path.join(__dirname, file), "utf-8");
 
-      const { parser, version } = getMarshaller(xml);
+      const { parser, version } = getMarshaller(xml, { upgradeTo: "latest" });
       const json = parser.parse();
 
       const minorVersion = version.split(".")[1];
diff --git a/packages/bpmn-marshaller/tests/versions.test.ts 
b/packages/bpmn-marshaller/tests/versions.test.ts
index 93aa3aaeca4..0f1e0bf2437 100644
--- a/packages/bpmn-marshaller/tests/versions.test.ts
+++ b/packages/bpmn-marshaller/tests/versions.test.ts
@@ -27,7 +27,7 @@ describe("versions", () => {
   for (const file of files) {
     test(path.basename(file.path), () => {
       const xml = fs.readFileSync(path.join(__dirname, file.path), "utf-8");
-      const { version } = getMarshaller(xml);
+      const { version } = getMarshaller(xml, { upgradeTo: "latest" });
       expect(version).toStrictEqual(file.version);
     });
   }
diff --git 
a/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/can-drive.dmn 
b/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/can-drive.dmn
index a1c669473f2..8acb1df4842 100644
--- a/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/can-drive.dmn
+++ b/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/can-drive.dmn
@@ -47,10 +47,6 @@
       <dmn:typeRef>number</dmn:typeRef>
     </dmn:itemComponent>
   </dmn:itemDefinition>
-  <dmn:inputData id="_66B82652-6454-4792-A989-7C97C4DF4672" name="Person">
-    <dmn:extensionElements />
-    <dmn:variable id="_6866698D-4B5B-44C2-952F-98EB982F16B6" name="Person" 
typeRef="tPerson" />
-  </dmn:inputData>
   <dmn:decision id="_753802DC-87F4-4485-81AE-E5393C61B1AC" name="Can drive?">
     <dmn:extensionElements />
     <dmn:variable id="_F1CBDD9A-1300-469A-A478-7A2D1C00C5B6" name="Can drive?" 
typeRef="boolean" />
@@ -159,6 +155,10 @@
       </dmn:rule>
     </dmn:decisionTable>
   </dmn:decision>
+  <dmn:inputData id="_66B82652-6454-4792-A989-7C97C4DF4672" name="Person">
+    <dmn:extensionElements />
+    <dmn:variable id="_6866698D-4B5B-44C2-952F-98EB982F16B6" name="Person" 
typeRef="tPerson" />
+  </dmn:inputData>
   <dmndi:DMNDI>
     <dmndi:DMNDiagram id="_1ED795B9-32EE-417C-8D14-C48D140B6ED5" name="DRG">
       <di:extension>
diff --git 
a/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/find-employees.dmn
 
b/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/find-employees.dmn
index 669fee27cbd..da32534b1e0 100644
--- 
a/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/find-employees.dmn
+++ 
b/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/find-employees.dmn
@@ -66,41 +66,6 @@
   <dmn:itemDefinition id="_8F50694C-1210-42B7-AB93-C839B8DA61CF" 
name="tKnowledges" isCollection="true">
     <dmn:typeRef>tKnowledge</dmn:typeRef>
   </dmn:itemDefinition>
-  <dmn:businessKnowledgeModel id="_F08537C6-DD4C-46F2-9709-61B43DF7AB0C" 
name="Find employee by knowledge">
-    <dmn:extensionElements />
-    <dmn:variable id="_87CC2587-114D-41AE-9D69-35DC313B8A47" name="Find 
employee by knowledge" typeRef="tEmployees" />
-    <dmn:encapsulatedLogic id="_243056C9-28EA-4EF2-8510-6F3BC6A5E5DC" 
kind="FEEL">
-      <dmn:formalParameter id="_FC4939B4-6414-4F17-8D8C-FE339EA9AC5D" 
name="employees" typeRef="tEmployees" />
-      <dmn:formalParameter id="_2B8160CE-1F54-42D7-B111-706FE3BF2012" 
name="knowledge" typeRef="tKnowledge" />
-      <dmn:formalParameter id="_810CD0CE-7F46-4827-B19B-BFBD543BB3D9" 
name="dept" typeRef="tDept" />
-      <dmn:context id="_1B96445B-523F-49B3-99BE-308A2F3CFBA5">
-        <dmn:contextEntry>
-          <dmn:variable id="_A762CB8E-56C3-45AE-B59F-731E4A0CA73F" 
name="Employees by" typeRef="tEmployees" />
-          <dmn:literalExpression id="_BC626016-B599-47A1-ABD6-67A2C7F761CE">
-            <dmn:text>employees[item.Dept = dept]</dmn:text>
-          </dmn:literalExpression>
-        </dmn:contextEntry>
-        <dmn:contextEntry>
-          <dmn:variable
-            id="_C772ADED-2499-4AF1-9C99-63AA17901EBB"
-            name="Employees with Knowledge"
-            typeRef="tEmployees"
-          />
-          <dmn:literalExpression id="_3543AF00-0F90-47C4-BCBF-6E3B28A08BD7">
-            <dmn:text>for e in Employees by return 
-if (list contains(e.Knowledges, knowledge))
-then e
-else null</dmn:text>
-          </dmn:literalExpression>
-        </dmn:contextEntry>
-        <dmn:contextEntry>
-          <dmn:literalExpression id="_049ECA86-1971-48B7-86FF-7E89B399074A">
-            <dmn:text>for e in Employees with Knowledge[item != null] return 
e</dmn:text>
-          </dmn:literalExpression>
-        </dmn:contextEntry>
-      </dmn:context>
-    </dmn:encapsulatedLogic>
-  </dmn:businessKnowledgeModel>
   <dmn:decision id="_7E27D2CF-13CA-4EF5-945C-0E7EB26E89CF" name="Employees">
     <dmn:extensionElements />
     <dmn:variable id="_C732DAF4-F690-42BF-BB38-5994AF7D4193" name="Employees" 
typeRef="tEmployees" />
@@ -206,6 +171,41 @@ else null</dmn:text>
       </dmn:binding>
     </dmn:invocation>
   </dmn:decision>
+  <dmn:businessKnowledgeModel id="_F08537C6-DD4C-46F2-9709-61B43DF7AB0C" 
name="Find employee by knowledge">
+    <dmn:extensionElements />
+    <dmn:variable id="_87CC2587-114D-41AE-9D69-35DC313B8A47" name="Find 
employee by knowledge" typeRef="tEmployees" />
+    <dmn:encapsulatedLogic id="_243056C9-28EA-4EF2-8510-6F3BC6A5E5DC" 
kind="FEEL">
+      <dmn:formalParameter id="_FC4939B4-6414-4F17-8D8C-FE339EA9AC5D" 
name="employees" typeRef="tEmployees" />
+      <dmn:formalParameter id="_2B8160CE-1F54-42D7-B111-706FE3BF2012" 
name="knowledge" typeRef="tKnowledge" />
+      <dmn:formalParameter id="_810CD0CE-7F46-4827-B19B-BFBD543BB3D9" 
name="dept" typeRef="tDept" />
+      <dmn:context id="_1B96445B-523F-49B3-99BE-308A2F3CFBA5">
+        <dmn:contextEntry>
+          <dmn:variable id="_A762CB8E-56C3-45AE-B59F-731E4A0CA73F" 
name="Employees by" typeRef="tEmployees" />
+          <dmn:literalExpression id="_BC626016-B599-47A1-ABD6-67A2C7F761CE">
+            <dmn:text>employees[item.Dept = dept]</dmn:text>
+          </dmn:literalExpression>
+        </dmn:contextEntry>
+        <dmn:contextEntry>
+          <dmn:variable
+            id="_C772ADED-2499-4AF1-9C99-63AA17901EBB"
+            name="Employees with Knowledge"
+            typeRef="tEmployees"
+          />
+          <dmn:literalExpression id="_3543AF00-0F90-47C4-BCBF-6E3B28A08BD7">
+            <dmn:text>for e in Employees by return 
+if (list contains(e.Knowledges, knowledge))
+then e
+else null</dmn:text>
+          </dmn:literalExpression>
+        </dmn:contextEntry>
+        <dmn:contextEntry>
+          <dmn:literalExpression id="_049ECA86-1971-48B7-86FF-7E89B399074A">
+            <dmn:text>for e in Employees with Knowledge[item != null] return 
e</dmn:text>
+          </dmn:literalExpression>
+        </dmn:contextEntry>
+      </dmn:context>
+    </dmn:encapsulatedLogic>
+  </dmn:businessKnowledgeModel>
   <dmn:inputData id="_FC002A20-9A6F-4461-A568-01946BE5CD6C" name="Dept">
     <dmn:extensionElements />
     <dmn:variable id="_7B025B6B-40F4-4E77-BEC6-712D72ED3A82" name="Dept" 
typeRef="tDept" />
diff --git 
a/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/loan-pre-qualification.dmn
 
b/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/loan-pre-qualification.dmn
index 85b41de564b..0b7d8fca8a5 100644
--- 
a/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/loan-pre-qualification.dmn
+++ 
b/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/loan-pre-qualification.dmn
@@ -157,19 +157,6 @@
       <dmn:typeRef>string</dmn:typeRef>
     </dmn:itemComponent>
   </dmn:itemDefinition>
-  <dmn:inputData id="_4C89E59C-FDDA-438C-8D1F-0B1194EF6DAE" name="Credit 
Score">
-    <dmn:extensionElements />
-    <dmn:variable id="_A97019FC-EE01-451F-A7AA-5A97ED005FB9" name="Credit 
Score" typeRef="Credit_Score" />
-  </dmn:inputData>
-  <dmn:businessKnowledgeModel id="_4C788DBD-C672-4F41-9AFE-9C7D2C145734" 
name="Lender Acceptable DTI">
-    <dmn:extensionElements />
-    <dmn:variable id="_85508943-7AD2-4AA0-80E5-20923CA2308D" name="Lender 
Acceptable DTI" typeRef="number" />
-    <dmn:encapsulatedLogic id="_9F0257EE-CF82-49FD-AEDD-3155890864FF" 
kind="FEEL">
-      <dmn:literalExpression id="_21E8FA38-C947-4733-9E52-CF81A97ADF91">
-        <dmn:text>0.36</dmn:text>
-      </dmn:literalExpression>
-    </dmn:encapsulatedLogic>
-  </dmn:businessKnowledgeModel>
   <dmn:decision id="_F0DC8923-5FC7-4200-8BD1-461D5F3714BE" name="Front End 
Ratio">
     <dmn:extensionElements />
     <dmn:variable id="_A0B0B032-F63F-491F-A65E-72E68A86B8FD" name="Front End 
Ratio" typeRef="Front_End_Ratio" />
@@ -228,23 +215,6 @@
       </dmn:contextEntry>
     </dmn:context>
   </dmn:decision>
-  <dmn:businessKnowledgeModel id="_FAF9080E-F4EF-49F7-AEFD-0D2990D8FFDA" 
name="PITI">
-    <dmn:extensionElements />
-    <dmn:variable id="_994F490E-10AC-4704-BFDA-14A3B98A981E" name="PITI" 
typeRef="number" />
-    <dmn:encapsulatedLogic id="_D33D9AEA-49DF-489F-98EC-4B42FF8C2027" 
kind="FEEL">
-      <dmn:formalParameter id="_664280C1-D5E0-47BE-82EF-0A6579975A62" 
name="pmt" typeRef="number" />
-      <dmn:formalParameter id="_3E7DF0B3-C48B-481D-B092-FC82EC2F6E37" 
name="tax" typeRef="number" />
-      <dmn:formalParameter id="_DF691F86-AD12-46BA-B149-AC875836A116" 
name="insurance" typeRef="number" />
-      <dmn:formalParameter id="_9E2E257F-90EB-4FC4-8DD9-089784E7579E" 
name="income" typeRef="number" />
-      <dmn:literalExpression id="_A32ED4A5-7B89-40F7-BE25-CDB636FE071C">
-        <dmn:text>(pmt+tax+insurance) / income</dmn:text>
-      </dmn:literalExpression>
-    </dmn:encapsulatedLogic>
-  </dmn:businessKnowledgeModel>
-  <dmn:inputData id="_1CF5CEFA-AF97-46F9-9CD5-9A8AEBB20B4E" name="Applicant 
Data">
-    <dmn:extensionElements />
-    <dmn:variable id="_2BBF28D2-DF09-4201-8D7A-5820E260592B" name="Applicant 
Data" typeRef="Applicant_Data" />
-  </dmn:inputData>
   <dmn:decision id="_D6F4234F-15B3-4F5B-B814-5F6FF29D2907" name="Back End 
Ratio">
     <dmn:extensionElements />
     <dmn:variable id="_5AF571F7-AD41-43DC-ABFD-26672585042F" name="Back End 
Ratio" typeRef="Back_End_Ratio" />
@@ -496,10 +466,28 @@
       </dmn:rule>
     </dmn:decisionTable>
   </dmn:decision>
-  <dmn:inputData id="_6E3205AF-7E3D-4ABE-A367-96F3F6E8210E" name="Requested 
Product">
+  <dmn:businessKnowledgeModel id="_4C788DBD-C672-4F41-9AFE-9C7D2C145734" 
name="Lender Acceptable DTI">
     <dmn:extensionElements />
-    <dmn:variable id="_EE05E1C7-67ED-4A71-BDEE-8005259351E8" name="Requested 
Product" typeRef="Requested_Product" />
-  </dmn:inputData>
+    <dmn:variable id="_85508943-7AD2-4AA0-80E5-20923CA2308D" name="Lender 
Acceptable DTI" typeRef="number" />
+    <dmn:encapsulatedLogic id="_9F0257EE-CF82-49FD-AEDD-3155890864FF" 
kind="FEEL">
+      <dmn:literalExpression id="_21E8FA38-C947-4733-9E52-CF81A97ADF91">
+        <dmn:text>0.36</dmn:text>
+      </dmn:literalExpression>
+    </dmn:encapsulatedLogic>
+  </dmn:businessKnowledgeModel>
+  <dmn:businessKnowledgeModel id="_FAF9080E-F4EF-49F7-AEFD-0D2990D8FFDA" 
name="PITI">
+    <dmn:extensionElements />
+    <dmn:variable id="_994F490E-10AC-4704-BFDA-14A3B98A981E" name="PITI" 
typeRef="number" />
+    <dmn:encapsulatedLogic id="_D33D9AEA-49DF-489F-98EC-4B42FF8C2027" 
kind="FEEL">
+      <dmn:formalParameter id="_664280C1-D5E0-47BE-82EF-0A6579975A62" 
name="pmt" typeRef="number" />
+      <dmn:formalParameter id="_3E7DF0B3-C48B-481D-B092-FC82EC2F6E37" 
name="tax" typeRef="number" />
+      <dmn:formalParameter id="_DF691F86-AD12-46BA-B149-AC875836A116" 
name="insurance" typeRef="number" />
+      <dmn:formalParameter id="_9E2E257F-90EB-4FC4-8DD9-089784E7579E" 
name="income" typeRef="number" />
+      <dmn:literalExpression id="_A32ED4A5-7B89-40F7-BE25-CDB636FE071C">
+        <dmn:text>(pmt+tax+insurance) / income</dmn:text>
+      </dmn:literalExpression>
+    </dmn:encapsulatedLogic>
+  </dmn:businessKnowledgeModel>
   <dmn:businessKnowledgeModel id="_DA5CCF62-90A8-4CFC-A137-98B528522588" 
name="DTI">
     <dmn:extensionElements />
     <dmn:variable id="_2F8921D1-6384-4ECB-848E-CE84A20B2573" name="DTI" 
typeRef="number" />
@@ -520,6 +508,18 @@
       </dmn:literalExpression>
     </dmn:encapsulatedLogic>
   </dmn:businessKnowledgeModel>
+  <dmn:inputData id="_4C89E59C-FDDA-438C-8D1F-0B1194EF6DAE" name="Credit 
Score">
+    <dmn:extensionElements />
+    <dmn:variable id="_A97019FC-EE01-451F-A7AA-5A97ED005FB9" name="Credit 
Score" typeRef="Credit_Score" />
+  </dmn:inputData>
+  <dmn:inputData id="_1CF5CEFA-AF97-46F9-9CD5-9A8AEBB20B4E" name="Applicant 
Data">
+    <dmn:extensionElements />
+    <dmn:variable id="_2BBF28D2-DF09-4201-8D7A-5820E260592B" name="Applicant 
Data" typeRef="Applicant_Data" />
+  </dmn:inputData>
+  <dmn:inputData id="_6E3205AF-7E3D-4ABE-A367-96F3F6E8210E" name="Requested 
Product">
+    <dmn:extensionElements />
+    <dmn:variable id="_EE05E1C7-67ED-4A71-BDEE-8005259351E8" name="Requested 
Product" typeRef="Requested_Product" />
+  </dmn:inputData>
   <dmndi:DMNDI>
     <dmndi:DMNDiagram id="_1608585F-01C8-4A66-B3E5-F4422D4DD2CA" name="DRG" 
useAlternativeInputDataShape="false">
       <di:extension>
diff --git a/packages/dmn-marshaller/src/schemas/kie-1_0/KIE.xsd 
b/packages/dmn-marshaller/src/schemas/kie-1_0/KIE.xsd
index 1a813d8a67c..f8d2ac66143 100644
--- a/packages/dmn-marshaller/src/schemas/kie-1_0/KIE.xsd
+++ b/packages/dmn-marshaller/src/schemas/kie-1_0/KIE.xsd
@@ -9,7 +9,7 @@
   <xsd:element name="ComponentsWidthsExtension" 
type="kie:tComponentsWidthsExtension" />
   <xsd:element name="ComponentWidths" type="kie:tComponentWidths" />
   <xsd:element name="attachment" type="kie:tAttachment" />
-  <xsd:attribute name="constraintType" type="tConstraintType" use="optional" />
+  <xsd:attribute name="constraintType" type="kie:tConstraintType" 
use="optional" />
 
   <xsd:complexType name="tComponentsWidthsExtension">
     <xsd:sequence>
diff --git a/packages/dmn-marshaller/tests/xsdSequence.test.ts 
b/packages/dmn-marshaller/tests/xsdSequence.test.ts
index c2aefe113b9..fc71f8c0964 100644
--- a/packages/dmn-marshaller/tests/xsdSequence.test.ts
+++ b/packages/dmn-marshaller/tests/xsdSequence.test.ts
@@ -106,9 +106,6 @@ describe("build always produces elements in the same 
order", () => {
       expect(marshaller.builder.build(json)).toStrictEqual(`<?xml 
version="1.0" encoding="UTF-8" ?>
 <definitions xmlns="https://www.omg.org/spec/DMN/20230324/MODEL/"; 
expressionLanguage="https://www.omg.org/spec/DMN/20230324/FEEL/"; 
namespace="https://kie.org/dmn/_D19C1092-7677-427F-A493-BCED38F74A9B"; 
id="_11655DE3-BEA5-45B1-B54E-8AD84FBBED25" 
name="DMN_1E889EDB-B967-4508-8DB1-E0DF5986E62F" 
xmlns:dmndi="https://www.omg.org/spec/DMN/20230324/DMNDI/"; 
xmlns:dc="http://www.omg.org/spec/DMN/20180521/DC/"; 
xmlns:di="http://www.omg.org/spec/DMN/20180521/DI/"; 
xmlns:kie="https://kie.org/dmn/extens [...]
   <import name="some-import" namespace="some-namespace" 
importType="some-import-type" />
-  <inputData name="New Input Data" id="_154F9E03-B180-4C87-B7D3-8745DA4336F4">
-    <variable name="New Input Data" id="_A28401DD-9A87-4251-A1E4-C63FC3A7C729" 
typeRef="string" />
-  </inputData>
   <decision name="New Decision" id="_392BEF3D-44B5-47DC-8A06-C36F15DB2984">
     <variable id="_C2C9C21A-E708-46D9-876A-52BB25692B66" typeRef="string" 
name="New Decision" />
     <informationRequirement id="_E781E253-D97E-4A1D-BE51-037B012B30F0">
@@ -118,6 +115,9 @@ describe("build always produces elements in the same 
order", () => {
       <text>&quot;New Decision&quot;</text>
     </literalExpression>
   </decision>
+  <inputData name="New Input Data" id="_154F9E03-B180-4C87-B7D3-8745DA4336F4">
+    <variable name="New Input Data" id="_A28401DD-9A87-4251-A1E4-C63FC3A7C729" 
typeRef="string" />
+  </inputData>
   <group name="some-group" />
   <dmndi:DMNDI>
     <dmndi:DMNDiagram id="_0D2FD42B-91FF-4795-B71F-E501CE115389" name="Default 
DRD" useAlternativeInputDataShape="false">
diff --git a/packages/react-hooks/src/usePreviousRef.ts 
b/packages/react-hooks/src/usePreviousRef.ts
index b5855874e6a..4504479fa9a 100644
--- a/packages/react-hooks/src/usePreviousRef.ts
+++ b/packages/react-hooks/src/usePreviousRef.ts
@@ -17,6 +17,7 @@
  * under the License.
  */
 
+import * as React from "react";
 import { useEffect, useRef } from "react";
 
 export function usePreviousRef<T>(value: T): React.MutableRefObject<T> {
diff --git a/packages/xml-parser-ts-codegen/README.md 
b/packages/xml-parser-ts-codegen/README.md
index e2c36fd49c0..c972f54006b 100644
--- a/packages/xml-parser-ts-codegen/README.md
+++ b/packages/xml-parser-ts-codegen/README.md
@@ -21,7 +21,7 @@ This package provides a Node.js script that generates 
TypeScript types and metad
 
 For more information about `@kie-tools/xml-parser-ts`, go to 
[../packages/xml-parser-ts](../xml-parser-ts/README.md)
 
-It was created to provide a way to marshall/unmarshall DMN, SceSim, BPMN, and 
PMML files, so it is only tested against those formats XSDs.
+It was created to provide a way to marshall/unmarshall BPMN, DMN, Test 
Scenario, and PMML files, so it is only tested against those formats XSDs.
 
 > NOTE: This package is probably not suited for your use-case, as it is 
 > incomplete and was not tested with a large number of XSD files, but it 
 > should work for simple XSDs. If you want to use it, please go ahead! Let us 
 > know if you tried and it worked! Feel free to contribute too with issues and 
 > PRs too.
 
diff --git a/packages/xml-parser-ts-codegen/src/codegen.ts 
b/packages/xml-parser-ts-codegen/src/codegen.ts
index c5054aebc12..f1c927f3cac 100644
--- a/packages/xml-parser-ts-codegen/src/codegen.ts
+++ b/packages/xml-parser-ts-codegen/src/codegen.ts
@@ -30,6 +30,8 @@ import {
   XptcComplexTypeAnonymous,
   XptcMetaType,
   XptcMetaTypeProperty,
+  XptcAttribute,
+  XptcTopLevelAttributeGroup,
 } from "./types";
 import {
   XsdAttribute,
@@ -143,29 +145,58 @@ async function main() {
 
   // // process <xsd:simpleType>'s
   const __SIMPLE_TYPES: XptcSimpleType[] = 
Array.from(__XSDS.entries()).flatMap(([location, schema]) =>
-    (schema["xsd:schema"]["xsd:simpleType"] || []).flatMap((s) => {
-      if (s["xsd:union"]) {
-        if (s["xsd:union"]["@_memberTypes"] === "xsd:anyURI") {
+    (schema["xsd:schema"]["xsd:simpleType"] || []).flatMap((xsdSimpleType) => {
+      if (xsdSimpleType["xsd:union"]) {
+        if (xsdSimpleType["xsd:union"]["@_memberTypes"] === "xsd:anyURI") {
           return [
             {
               comment: "xsd:anyURI",
               type: "simple",
               kind: "enum",
-              name: s["@_name"] ?? s["@_name"],
+              name: xsdSimpleType["@_name"]!,
               declaredAtRelativeLocation: location,
               values: [],
             },
           ];
         }
-        return (s["xsd:union"]["xsd:simpleType"] ?? []).flatMap((ss) =>
-          xsdSimpleTypeToXptcSimpleType(ss, location, s["@_name"])
+        return (xsdSimpleType["xsd:union"]["xsd:simpleType"] ?? 
[]).flatMap((ss) =>
+          xsdSimpleTypeToXptcSimpleType(ss, location, xsdSimpleType["@_name"]!)
         );
       } else {
-        return xsdSimpleTypeToXptcSimpleType(s, location, s["@_name"]);
+        return xsdSimpleTypeToXptcSimpleType(xsdSimpleType, location, 
xsdSimpleType["@_name"]!);
       }
     })
   );
 
+  const __ATTRIBUTE_GROUPS_BY_QNAME: Map<string, XptcTopLevelAttributeGroup> = 
new Map(
+    Array.from(__XSDS.entries()).flatMap(([location, schema]) =>
+      (schema["xsd:schema"]["xsd:attributeGroup"] || 
[]).flatMap((xsdAttrGroup) => {
+        const qNamePrefix = Object.keys(schema["xsd:schema"])
+          .find(
+            (key: keyof (typeof schema)["xsd:schema"]) =>
+              key.startsWith("@_xmlns:") && // is a xml namespace declaration
+              schema["xsd:schema"][key] === 
schema["xsd:schema"]["@_targetNamespace"]
+          )
+          ?.split(":")[1];
+        if (!qNamePrefix) {
+          return [];
+        }
+
+        return [
+          [
+            `${qNamePrefix}:${xsdAttrGroup["@_name"]}`,
+            {
+              name: xsdAttrGroup["@_name"],
+              attributes: (xsdAttrGroup["xsd:attribute"] ?? []).map((xsdAttr) 
=>
+                xsdAttributeToXptcAttribute(xsdAttr, location)
+              ),
+            },
+          ],
+        ];
+      })
+    )
+  );
+
   // // process <xsd:complexType>'s
   const __COMPLEX_TYPES: XptcComplexType[] = [];
   for (const [location, xsd] of __XSDS.entries()) {
@@ -177,6 +208,7 @@ async function main() {
       __COMPLEX_TYPES.push({
         type: "complex",
         comment: isAbstract ? "abstract" : "",
+        isMixed: xsdCt["@_mixed"] ?? false,
         isAbstract,
         isAnonymous: false,
         name: xsdCt["@_name"]!,
@@ -186,27 +218,30 @@ async function main() {
         childOf: extensionElement?.["@_base"],
         elements: [
           ...(xsdCt["xsd:all"]?.["xsd:element"] ?? []).map((s) =>
-            xsdElementToXptcElement(xsdCt["@_name"]!, s, location)
+            xsdElementToXptcElement(__ATTRIBUTE_GROUPS_BY_QNAME, 
xsdCt["@_name"]!, s, location)
           ),
           ...(xsdCt["xsd:sequence"]?.["xsd:element"] ?? []).map((s) =>
-            xsdElementToXptcElement(xsdCt["@_name"]!, s, location)
+            xsdElementToXptcElement(__ATTRIBUTE_GROUPS_BY_QNAME, 
xsdCt["@_name"]!, s, location)
           ),
           ...(extensionElement?.["xsd:sequence"]?.["xsd:element"] ?? 
[]).map((s) =>
-            xsdElementToXptcElement(xsdCt["@_name"]!, s, location)
+            xsdElementToXptcElement(__ATTRIBUTE_GROUPS_BY_QNAME, 
xsdCt["@_name"]!, s, location)
           ),
           
...(extensionElement?.["xsd:sequence"]?.["xsd:choice"]?.["xsd:element"] ?? 
[]).map((s) =>
-            xsdElementToXptcElement(xsdCt["@_name"]!, s, location, { 
forceOptional: true })
+            xsdElementToXptcElement(__ATTRIBUTE_GROUPS_BY_QNAME, 
xsdCt["@_name"]!, s, location, { forceOptional: true })
           ),
           ...(extensionElement?.["xsd:choice"]?.["xsd:element"] ?? []).map((s) 
=>
-            xsdElementToXptcElement(xsdCt["@_name"]!, s, location, { 
forceOptional: true })
+            xsdElementToXptcElement(__ATTRIBUTE_GROUPS_BY_QNAME, 
xsdCt["@_name"]!, s, location, { forceOptional: true })
           ),
           
...(extensionElement?.["xsd:choice"]?.["xsd:sequence"]?.["xsd:element"] ?? 
[]).map((s) =>
-            xsdElementToXptcElement(xsdCt["@_name"]!, s, location, { 
forceOptional: true })
+            xsdElementToXptcElement(__ATTRIBUTE_GROUPS_BY_QNAME, 
xsdCt["@_name"]!, s, location, { forceOptional: true })
           ),
         ],
         attributes: [
-          ...(xsdCt["xsd:attribute"] ?? []).map((a) => 
xsdAttributeToXptcAttribute(a)),
-          ...(extensionElement?.["xsd:attribute"] ?? []).map((a) => 
xsdAttributeToXptcAttribute(a)),
+          ...(xsdCt["xsd:attribute"] ?? []).map((a) => 
xsdAttributeToXptcAttribute(a, location)),
+          ...(extensionElement?.["xsd:attribute"] ?? []).map((a) => 
xsdAttributeToXptcAttribute(a, location)),
+          ...(xsdCt["xsd:attributeGroup"] ?? []).flatMap(
+            (attrGroup) => 
__ATTRIBUTE_GROUPS_BY_QNAME.get(attrGroup["@_ref"])?.attributes ?? []
+          ),
         ],
       });
     }
@@ -216,13 +251,42 @@ async function main() {
   const __GLOBAL_ELEMENTS = new Map<string, XptcElement>();
   for (const [location, xsd] of __XSDS.entries()) {
     for (const e of xsd["xsd:schema"]["xsd:element"] || []) {
-      const a = xsdElementToXptcElement("GLOBAL", { ...e, "@_minOccurs": 0, 
"@_maxOccurs": "unbounded" }, location, {
-        forceOptional: false,
-      });
+      const a = xsdElementToXptcElement(
+        __ATTRIBUTE_GROUPS_BY_QNAME,
+        "GLOBAL",
+        { ...e, "@_minOccurs": 0, "@_maxOccurs": "unbounded" },
+        location,
+        {
+          forceOptional: false,
+        }
+      );
+
+      let isAbstract = e["@_abstract"];
+      if (a.kind === "ofNamedType") {
+        const split = a.typeName?.split(":") ?? [];
+        const qNamePrefix = split.length === 2 ? split[0] : undefined;
+        const typeName = split.length === 2 ? split[1] : split[0];
+        const namespace = xsd["xsd:schema"][`@_xmlns:${qNamePrefix}`];
+        const [typeXsdLocation, typeXsd] =
+          [...__XSDS.entries()].find(([location, xsd]) => 
xsd["xsd:schema"]["@_targetNamespace"] === namespace) ?? [];
+
+        const type = __COMPLEX_TYPES
+          .filter((s) => !s.isAnonymous)
+          .filter((s) => (qNamePrefix ? s.declaredAtRelativeLocation === 
typeXsdLocation : true))
+          .find((s) => s.name === typeName);
+
+        if (!type) {
+          throw new Error(`Can't find type '${typeName}' for element 
${e["@_name"]}`);
+        }
+
+        isAbstract ??= type?.isAbstract;
+      }
+
+      isAbstract ??= false;
 
       __GLOBAL_ELEMENTS.set(`${location}__${e["@_name"]}`, {
         name: e["@_name"],
-        isAbstract: e["@_abstract"] ?? false,
+        isAbstract,
         substitutionGroup: e["@_substitutionGroup"],
         type: e["@_type"],
         declaredAtRelativeLocation: location,
@@ -242,7 +306,7 @@ async function main() {
       __SUBSTITUTIONS.set(xLocation, localizedSubstitutions);
       for (const e of xsd["xsd:schema"]["xsd:element"] || []) {
         if (e["@_substitutionGroup"]) {
-          const subsGroup = getXptcElementFromLocalElementRef(
+          const subsGroup = getXptcElementFromElementQName(
             __XSDS,
             __GLOBAL_ELEMENTS,
             xLocation,
@@ -251,7 +315,7 @@ async function main() {
           if (!subsGroup) {
             throw new Error(`Invalid subsitution group for element 
'${e["@_name"]}'`);
           }
-          const elem = getXptcElementFromLocalElementRef(__XSDS, 
__GLOBAL_ELEMENTS, xLocation, e["@_name"]);
+          const elem = getXptcElementFromElementQName(__XSDS, 
__GLOBAL_ELEMENTS, xLocation, e["@_name"]);
           if (!elem) {
             throw new Error(`Invalid element '${e["@_name"]}'`);
           }
@@ -262,6 +326,7 @@ async function main() {
           const accumulatedSubstitutionElements = new Set([
             ...(localizedSubstitutions.get(localizedElementName) ?? []),
             `${xLocation}__${elem.name}`,
+            ...(subsGroup.isAbstract ? [] : [localizedElementName]), // 
Include itself if not abstract
           ]);
 
           localizedSubstitutions.set(localizedElementName, 
[...accumulatedSubstitutionElements]);
@@ -435,10 +500,14 @@ ${Array.from(subs.entries())
   .map(
     ([head, elements]) =>
       `${elements
-        .map((e) => {
+        .flatMap((e) => {
           const elementName = `${getRealtiveLocationNs(__RELATIVE_LOCATION, 
e.split("__")[0]) + e.split("__")[1]}`;
           const headName = `${getRealtiveLocationNs(__RELATIVE_LOCATION, 
head.split("__")[0]) + head.split("__")[1]}`;
-          return `    "${elementName}": "${headName}",`;
+          if (elementName === headName) {
+            return []; // Do not serialize itself as a substitution.
+          } else {
+            return `    "${elementName}": "${headName}",`;
+          }
         })
         .join("\n")}`
   )
@@ -510,12 +579,36 @@ function resolveElementRef(
     return [referencedElement];
   }
 
-  return 
substitutionNamesForReferencedElement.flatMap((substitutionElementName) => {
+  const substitutionsWithoutSelfReferences = new Map(
+    [...substitutions.entries()].map(([key, value]) => [key, value.filter((v) 
=> v !== key)] as const)
+  );
+
+  const resolved = 
substitutionNamesForReferencedElement.flatMap((substitutionElementName) => {
     const substitutionElement = __GLOBAL_ELEMENTS.get(substitutionElementName);
     if (!substitutionElement) {
       throw new Error(`Can't find element '${substitutionElementName}' for 
substitution ${key}`);
     }
-    return resolveElementRef(__GLOBAL_ELEMENTS, __XSDS, substitutions, 
substitutionElement);
+
+    if (substitutionElement.isAbstract) {
+      return resolveElementRef(__GLOBAL_ELEMENTS, __XSDS, 
substitutionsWithoutSelfReferences, substitutionElement);
+    }
+
+    // Include itself if not abstract.
+    return [
+      substitutionElement,
+      ...resolveElementRef(__GLOBAL_ELEMENTS, __XSDS, 
substitutionsWithoutSelfReferences, substitutionElement),
+    ];
+  });
+
+  const seen = new Set<string>();
+  return resolved.filter((s) => {
+    const key = `${s.declaredAtRelativeLocation}__${s.name}`;
+    if (seen.has(key)) {
+      return false;
+    } else {
+      seen.add(key);
+      return true;
+    }
   });
 }
 
@@ -552,7 +645,7 @@ ${resolutions
     const elementName = `${elementNs}${element.name}`;
     return [
       `        ({ __$$element: "${elementName}" } & ${
-        getTsTypeFromLocalRef(
+        getTsTypeFromQName(
           __XSDS,
           __NAMED_TYPES_BY_TS_NAME,
           ct.declaredAtRelativeLocation,
@@ -582,13 +675,15 @@ function getMetaProperties(
   const anonymousTypes: XptcMetaType[] = [];
 
   const immediateParentType = ct.childOf
-    ? getTsTypeFromLocalRef(__XSDS, __NAMED_TYPES_BY_TS_NAME, 
ct.declaredAtRelativeLocation, ct.childOf)
+    ? getTsTypeFromQName(__XSDS, __NAMED_TYPES_BY_TS_NAME, 
ct.declaredAtRelativeLocation, ct.childOf)
     : undefined;
 
   let curParentCt = immediateParentType ? 
__NAMED_TYPES_BY_TS_NAME.get(immediateParentType.name) : undefined;
 
   let needsExtensionType = ct.needsExtensionType;
 
+  let isMixed = ct.isMixed;
+
   while (curParentCt) {
     const curParentCtMetaProperties: XptcMetaTypeProperty[] = [];
     if (curParentCt?.type === "complex") {
@@ -601,8 +696,10 @@ function getMetaProperties(
         throw new Error("Anonymous types are never parent types.");
       }
 
+      isMixed ||= curParentCt.isMixed;
+
       for (const a of curParentCt.attributes) {
-        const attributeType = getTsTypeFromLocalRef(
+        const attributeType = getTsTypeFromQName(
           __XSDS,
           __NAMED_TYPES_BY_TS_NAME,
           curParentCt.declaredAtRelativeLocation,
@@ -652,7 +749,7 @@ function getMetaProperties(
             isOptional: e.isOptional,
           });
         } else if (e.kind === "ofNamedType") {
-          const tsType = getTsTypeFromLocalRef(
+          const tsType = getTsTypeFromQName(
             __XSDS,
             __NAMED_TYPES_BY_TS_NAME,
             ct.declaredAtRelativeLocation,
@@ -670,7 +767,7 @@ function getMetaProperties(
             isOptional: e.isOptional,
           });
         } else if (e.kind === "ofRef") {
-          const referencedElement = getXptcElementFromLocalElementRef(
+          const referencedElement = getXptcElementFromElementQName(
             __XSDS,
             __GLOBAL_ELEMENTS,
             ct.declaredAtRelativeLocation,
@@ -682,7 +779,7 @@ function getMetaProperties(
           }
 
           const tsType = referencedElement.type
-            ? getTsTypeFromLocalRef(
+            ? getTsTypeFromQName(
                 __XSDS,
                 __NAMED_TYPES_BY_TS_NAME,
                 ct.declaredAtRelativeLocation,
@@ -722,7 +819,7 @@ function getMetaProperties(
       }
 
       const nextParentType = curParentCt.childOf
-        ? getTsTypeFromLocalRef(
+        ? getTsTypeFromQName(
             __XSDS,
             __NAMED_TYPES_BY_TS_NAME,
             curParentCt.declaredAtRelativeLocation,
@@ -744,7 +841,7 @@ function getMetaProperties(
   // Own properties are parsed later to ensure xsd:sequence order.
 
   for (const a of ct.attributes) {
-    const attributeType = getTsTypeFromLocalRef(
+    const attributeType = getTsTypeFromQName(
       __XSDS,
       __NAMED_TYPES_BY_TS_NAME,
       ct.declaredAtRelativeLocation,
@@ -764,7 +861,7 @@ function getMetaProperties(
 
   for (const e of ct.elements) {
     if (e.kind === "ofRef") {
-      const referencedElement = getXptcElementFromLocalElementRef(
+      const referencedElement = getXptcElementFromElementQName(
         __XSDS,
         __GLOBAL_ELEMENTS,
         ct.declaredAtRelativeLocation,
@@ -776,7 +873,7 @@ function getMetaProperties(
       }
 
       const tsType = referencedElement.type
-        ? getTsTypeFromLocalRef(__XSDS, __NAMED_TYPES_BY_TS_NAME, 
ct.declaredAtRelativeLocation, referencedElement.type)
+        ? getTsTypeFromQName(__XSDS, __NAMED_TYPES_BY_TS_NAME, 
ct.declaredAtRelativeLocation, referencedElement.type)
         : {
             name: getTsNameFromNamedType(
               ct.declaredAtRelativeLocation,
@@ -806,7 +903,7 @@ function getMetaProperties(
         isOptional: e.isOptional,
       });
     } else if (e.kind === "ofNamedType") {
-      const tsType = getTsTypeFromLocalRef(__XSDS, __NAMED_TYPES_BY_TS_NAME, 
ct.declaredAtRelativeLocation, e.typeName);
+      const tsType = getTsTypeFromQName(__XSDS, __NAMED_TYPES_BY_TS_NAME, 
ct.declaredAtRelativeLocation, e.typeName);
       ctMetaProperties.push({
         declaredAt: ct.declaredAtRelativeLocation,
         fromType: metaTypeName,
@@ -850,7 +947,7 @@ function getMetaProperties(
   }
 
   if (ct.isSimpleContent && ct.childOf) {
-    const t = getTsTypeFromLocalRef(__XSDS, __NAMED_TYPES_BY_TS_NAME, 
ct.declaredAtRelativeLocation, ct.childOf);
+    const t = getTsTypeFromQName(__XSDS, __NAMED_TYPES_BY_TS_NAME, 
ct.declaredAtRelativeLocation, ct.childOf);
     ctMetaProperties.push({
       declaredAt: ct.declaredAtRelativeLocation,
       fromType: metaTypeName,
@@ -865,6 +962,21 @@ function getMetaProperties(
     });
   }
 
+  if (isMixed) {
+    ctMetaProperties.push({
+      declaredAt: ct.declaredAtRelativeLocation,
+      fromType: metaTypeName,
+      name: `__$$text`,
+      elem: undefined,
+      metaType: {
+        name: "string",
+        xsdType: "xsd:string",
+      },
+      isArray: false,
+      isOptional: true,
+    });
+  }
+
   if (!(ct.type === "complex" && !ct.isAnonymous && ct.isAbstract)) {
     __META_TYPE_MAPPING.set(metaTypeName, {
       name: metaTypeName,
@@ -884,23 +996,23 @@ function getTsNameFromNamedType(relativeLocation: string, 
namedTypeName: string)
   return `${filenameWithoutExtension}__${namedTypeName}`.replaceAll(/[ -.]/g, 
"_");
 }
 
-function getTsTypeFromLocalRef(
+function getTsTypeFromQName(
   __XSDS: Map<string, XsdSchema>,
   __NAMED_TYPES_BY_TS_NAME: Map<string, XptcComplexType | XptcSimpleType>,
   relativeLocation: string,
-  namedTypeLocalRef: string
+  namedTypeQName: string
 ): { name: string; annotation: string } {
   // check if it's a local ref to another namespace
-  if (namedTypeLocalRef.includes(":") && namedTypeLocalRef.split(":").length 
=== 2) {
-    const [localNsName, namedTypeName] = namedTypeLocalRef.split(":");
+  if (namedTypeQName.includes(":") && namedTypeQName.split(":").length === 2) {
+    const [localNsName, namedTypeName] = namedTypeQName.split(":");
     const xmlnsKey = `@_xmlns:${localNsName}`;
     const namespace = (__XSDS.get(relativeLocation)?.["xsd:schema"] as 
any)[xmlnsKey];
 
     // short circuit here. we don't parse XSD's XSD.
     if (namespace === "http://www.w3.org/2001/XMLSchema";) {
-      const xsdType = XSD__TYPES.get(namedTypeLocalRef);
+      const xsdType = XSD__TYPES.get(namedTypeQName);
       if (!xsdType) {
-        throw new Error(`Unknown XSD type '${namedTypeLocalRef}'`);
+        throw new Error(`Unknown XSD type '${namedTypeQName}'`);
       }
       return { name: xsdType.tsEquivalent, annotation: xsdType.annotation };
     }
@@ -922,7 +1034,7 @@ function getTsTypeFromLocalRef(
 
     // some simple types are declared just because of the restrictions it has, 
they're not interesting for the generated structure.
     if (namedType.type === "simple" && namedType.kind === "int" && 
namedType.restrictionBase) {
-      return getTsTypeFromLocalRef(__XSDS, __NAMED_TYPES_BY_TS_NAME, 
relativeLocation, namedType.restrictionBase);
+      return getTsTypeFromQName(__XSDS, __NAMED_TYPES_BY_TS_NAME, 
relativeLocation, namedType.restrictionBase);
     }
 
     // found it!
@@ -931,49 +1043,66 @@ function getTsTypeFromLocalRef(
 
   // not a reference to a type in another namespace. simply local name.
   return {
-    name: getTsNameFromNamedType(relativeLocation, namedTypeLocalRef),
+    name: getTsNameFromNamedType(relativeLocation, namedTypeQName),
     annotation: "// local type",
   };
 }
 
-function xsdSimpleTypeToXptcSimpleType(s: XsdSimpleType, location: string, 
name: string): XptcSimpleType {
+function xsdSimpleTypeToXptcSimpleType(
+  xsdSimpleType: XsdSimpleType,
+  location: string,
+  nameIfUnnamed: string
+): XptcSimpleType {
   if (
-    (s["xsd:restriction"]?.["@_base"] === "xsd:string" || 
s["xsd:restriction"]?.["@_base"] === "xsd:token") &&
-    s["xsd:restriction"]["xsd:enumeration"]
+    xsdSimpleType["xsd:restriction"]?.["@_base"] === "xsd:string" ||
+    xsdSimpleType["xsd:restriction"]?.["@_base"] === "xsd:token"
+  ) {
+    if (xsdSimpleType["xsd:restriction"]["xsd:enumeration"]) {
+      return {
+        comment: "enum",
+        type: "simple",
+        kind: "enum",
+        name: xsdSimpleType["@_name"] ?? nameIfUnnamed,
+        declaredAtRelativeLocation: location,
+        values: xsdSimpleType["xsd:restriction"]["xsd:enumeration"].map((e) => 
e["@_value"]),
+      };
+    } else {
+      return {
+        comment: "string",
+        type: "simple",
+        kind: "string",
+        name: xsdSimpleType["@_name"] ?? nameIfUnnamed,
+        declaredAtRelativeLocation: location,
+      };
+    }
+  } else if (
+    xsdSimpleType["xsd:restriction"]?.["@_base"] === "xsd:int" ||
+    xsdSimpleType["xsd:restriction"]?.["@_base"] === "xsd:integer"
   ) {
-    return {
-      comment: "enum",
-      type: "simple",
-      kind: "enum",
-      name: s["@_name"] ?? name,
-      declaredAtRelativeLocation: location,
-      values: s["xsd:restriction"]["xsd:enumeration"].map((e) => e["@_value"]),
-    };
-  } else if (s["xsd:restriction"]?.["@_base"] === "xsd:int" || 
s["xsd:restriction"]?.["@_base"] === "xsd:integer") {
     return {
       comment: "int",
       type: "simple",
       kind: "int",
-      restrictionBase: s["xsd:restriction"]["@_base"],
-      name: s["@_name"] ?? name,
+      restrictionBase: xsdSimpleType["xsd:restriction"]["@_base"],
+      name: xsdSimpleType["@_name"] ?? nameIfUnnamed,
       declaredAtRelativeLocation: location,
-      minInclusive: s["xsd:restriction"]["xsd:minInclusive"]?.["@_value"],
-      maxInclusive: s["xsd:restriction"]["xsd:maxInclusive"]?.["@_value"],
+      minInclusive: 
xsdSimpleType["xsd:restriction"]["xsd:minInclusive"]?.["@_value"],
+      maxInclusive: 
xsdSimpleType["xsd:restriction"]["xsd:maxInclusive"]?.["@_value"],
     };
   } else {
-    throw new Error(`Unknown xsd:simpleType --> ${JSON.stringify(s, undefined, 
2)}`);
+    throw new Error(`Unknown xsd:simpleType --> 
${JSON.stringify(xsdSimpleType, undefined, 2)}`);
   }
 }
 
-function getXptcElementFromLocalElementRef(
+function getXptcElementFromElementQName(
   __XSDS: Map<string, XsdSchema>,
   __GLOBAL_ELEMENTS: Map<string, XptcElement>,
   relativeLocation: string,
-  localElementRef: string
+  elementQName: string
 ): XptcElement | undefined {
   // check if it's a QName to another namespace
-  if (localElementRef.includes(":") && localElementRef.split(":").length === 
2) {
-    const [localNsName, referencedElementName] = localElementRef.split(":");
+  if (elementQName.includes(":") && elementQName.split(":").length === 2) {
+    const [localNsName, referencedElementName] = elementQName.split(":");
     const xmlnsKey = `@_xmlns:${localNsName}`;
     const namespace = (__XSDS.get(relativeLocation)?.["xsd:schema"] as 
any)[xmlnsKey];
 
@@ -988,10 +1117,11 @@ function getXptcElementFromLocalElementRef(
     return 
__GLOBAL_ELEMENTS.get(`${referencedXsdRelativeLocation}__${referencedElementName}`);
   }
 
-  return __GLOBAL_ELEMENTS.get(`${relativeLocation}__${localElementRef}`);
+  return __GLOBAL_ELEMENTS.get(`${relativeLocation}__${elementQName}`);
 }
 
 function xsdElementToXptcElement(
+  __ATTRIBUTE_GROUPS_BY_QNAME: Map<string, XptcTopLevelAttributeGroup>,
   parentIdentifierForExtensionType: string,
   xsdElement: NonNullable<Unpacked<XsdSequence["xsd:element"]>>,
   location: string,
@@ -1067,6 +1197,7 @@ function xsdElementToXptcElement(
       isArray,
       isOptional,
       anonymousType: xsdComplexTypeToAnonymousXptcComplexType(
+        __ATTRIBUTE_GROUPS_BY_QNAME,
         parentIdentifierForExtensionType,
         xsdElement["xsd:complexType"],
         location,
@@ -1091,15 +1222,19 @@ function xsdElementToXptcElement(
   throw new Error(`Unknown xsd:element structure. 
${JSON.stringify(xsdElement)}`);
 }
 
-function xsdAttributeToXptcAttribute(xsdAttribute: XsdAttribute): 
Unpacked<XptcComplexType["attributes"]> {
+function xsdAttributeToXptcAttribute(xsdAttribute: XsdAttribute, location: 
string): XptcAttribute {
   return {
     name: xsdAttribute["@_name"],
     localTypeRef: xsdAttribute["@_type"],
     isOptional: xsdAttribute["@_use"] === undefined || xsdAttribute["@_use"] 
=== "optional",
+    simpleType: xsdAttribute["xsd:simpleType"]
+      ? xsdSimpleTypeToXptcSimpleType(xsdAttribute["xsd:simpleType"], 
location, `${xsdAttribute["@_name"]}simpleType`)
+      : undefined,
   };
 }
 
 function xsdComplexTypeToAnonymousXptcComplexType(
+  __ATTRIBUTE_GROUPS_BY_QNAME: Map<string, XptcTopLevelAttributeGroup>,
   parentIdentifierForExtensionType: string,
   xsdCt: XsdComplexType,
   location: string,
@@ -1108,6 +1243,7 @@ function xsdComplexTypeToAnonymousXptcComplexType(
   return {
     type: "complex",
     comment: "",
+    isMixed: xsdCt["@_mixed"] ?? false,
     isSimpleContent: false, // No reason why an anonymous type couldn't be 
simpleContent... Could be implemented.
     isAnonymous: true,
     parentIdentifierForExtensionType,
@@ -1117,16 +1253,29 @@ function xsdComplexTypeToAnonymousXptcComplexType(
     childOf: xsdCt["xsd:complexContent"]?.["xsd:extension"]?.["@_base"],
     elements: [
       ...(xsdCt["xsd:sequence"]?.["xsd:element"] ?? []).map((s) =>
-        
xsdElementToXptcElement(`${parentIdentifierForExtensionType}__${element}`, s, 
location)
+        xsdElementToXptcElement(
+          __ATTRIBUTE_GROUPS_BY_QNAME,
+          `${parentIdentifierForExtensionType}__${element}`,
+          s,
+          location
+        )
       ),
       
...(xsdCt["xsd:complexContent"]?.["xsd:extension"]?.["xsd:sequence"]?.["xsd:element"]
 ?? []).map((s) =>
-        
xsdElementToXptcElement(`${parentIdentifierForExtensionType}__${element}`, s, 
location)
+        xsdElementToXptcElement(
+          __ATTRIBUTE_GROUPS_BY_QNAME,
+          `${parentIdentifierForExtensionType}__${element}`,
+          s,
+          location
+        )
       ),
     ],
     attributes: [
-      ...(xsdCt["xsd:attribute"] ?? []).map((a) => 
xsdAttributeToXptcAttribute(a)),
+      ...(xsdCt["xsd:attribute"] ?? []).map((a) => 
xsdAttributeToXptcAttribute(a, location)),
       ...(xsdCt["xsd:complexContent"]?.["xsd:extension"]?.["xsd:attribute"] ?? 
[]).map((a) =>
-        xsdAttributeToXptcAttribute(a)
+        xsdAttributeToXptcAttribute(a, location)
+      ),
+      ...(xsdCt["xsd:attributeGroup"] ?? []).flatMap(
+        (attrGroup) => 
__ATTRIBUTE_GROUPS_BY_QNAME.get(attrGroup["@_ref"])?.attributes ?? []
       ),
     ],
   };
diff --git 
a/packages/xml-parser-ts-codegen/src/schemas/xsd-incomplete--manually-written/ts-gen/meta.ts
 
b/packages/xml-parser-ts-codegen/src/schemas/xsd-incomplete--manually-written/ts-gen/meta.ts
index 7cce79edc45..9e42df5e336 100644
--- 
a/packages/xml-parser-ts-codegen/src/schemas/xsd-incomplete--manually-written/ts-gen/meta.ts
+++ 
b/packages/xml-parser-ts-codegen/src/schemas/xsd-incomplete--manually-written/ts-gen/meta.ts
@@ -34,6 +34,8 @@ export const meta = {
     "xsd:annotation": { type: "annotation", isArray: true, fromType: "", 
xsdType: "" },
     "xsd:simpleType": { type: "simpleType", isArray: true, fromType: "", 
xsdType: "" },
     "xsd:complexType": { type: "complexType", isArray: true, fromType: "", 
xsdType: "" },
+    "xsd:attributeGroup": { type: "topLevelAttributeGroup", isArray: true, 
fromType: "", xsdType: "" },
+    "xsd:attribute": { type: "attribute", isArray: true, fromType: "", 
xsdType: "" },
   },
   all: {
     "@_minOccurs": { type: "integer", isArray: false, fromType: "", xsdType: 
"" },
@@ -49,7 +51,17 @@ export const meta = {
   union: {
     "xsd:simpleType": { type: "simpleType", isArray: true, fromType: "", 
xsdType: "" },
   },
-  attribute: {},
+  attribute: {
+    "@_name": { type: "string", isArray: false, fromType: "", xsdType: "" },
+    "xsd:simpleType": { type: "simpleType", isArray: false, fromType: "", 
xsdType: "" },
+  },
+  topLevelAttributeGroup: {
+    "@_name": { type: "string", isArray: false, fromType: "", xsdType: "" },
+    "xsd:attribute": { type: "attribute", isArray: true, fromType: "", 
xsdType: "" },
+  },
+  attributeGroup: {
+    "@_ref": { type: "string", isArray: false, fromType: "", xsdType: "" },
+  },
   element: {
     "@_abstract": { type: "boolean", isArray: false, fromType: "", xsdType: "" 
},
     "@_minOccurs": { type: "integer", isArray: false, fromType: "", xsdType: 
"" },
@@ -58,11 +70,13 @@ export const meta = {
   },
   complexType: {
     "@_abstract": { type: "boolean", isArray: false, fromType: "", xsdType: "" 
},
+    "@_mixed": { type: "boolean", isArray: false, fromType: "", xsdType: "" },
     "xsd:complexContent": { type: "complexContent", isArray: false, fromType: 
"", xsdType: "" },
     "xsd:simpleContent": { type: "simpleContent", isArray: false, fromType: 
"", xsdType: "" },
     "xsd:sequence": { type: "sequence", isArray: false, fromType: "", xsdType: 
"" },
     "xsd:all": { type: "all", isArray: false, fromType: "", xsdType: "" },
     "xsd:attribute": { type: "attribute", isArray: true, fromType: "", 
xsdType: "" },
+    "xsd:attributeGroup": { type: "attributeGroup", isArray: true, fromType: 
"", xsdType: "" },
   },
   complexContent: {
     "xsd:extension": { type: "extension", isArray: false, fromType: "", 
xsdType: "" },
diff --git 
a/packages/xml-parser-ts-codegen/src/schemas/xsd-incomplete--manually-written/ts-gen/types.d.ts
 
b/packages/xml-parser-ts-codegen/src/schemas/xsd-incomplete--manually-written/ts-gen/types.d.ts
index 21d5daa83d9..98552a69d6a 100644
--- 
a/packages/xml-parser-ts-codegen/src/schemas/xsd-incomplete--manually-written/ts-gen/types.d.ts
+++ 
b/packages/xml-parser-ts-codegen/src/schemas/xsd-incomplete--manually-written/ts-gen/types.d.ts
@@ -17,6 +17,8 @@
  * under the License.
  */
 
+import { XmlParserTsRootElementBaseType } from "@kie-tools/xml-parser-ts";
+
 export type XsdPrimitives = "xsd:int" | "xsd:string" | "xsd:token" | 
"xsd:integer" | "xsd:anyURI";
 
 export interface XsdImport {
@@ -28,7 +30,7 @@ export interface XsdImport {
 }
 
 export interface XsdSimpleType {
-  "@_name": string;
+  "@_name"?: string;
   "xsd:union"?: {
     "@_memberTypes": XsdPrimitives;
     "xsd:simpleType"?: XsdSimpleType[];
@@ -47,6 +49,12 @@ export interface XsdAttribute {
   "@_type": string;
   "@_use"?: "required" | "optional";
   "@_default": string;
+  "xsd:simpleType"?: XsdSimpleType;
+}
+
+export interface XsdTopLevelAttributeGroup {
+  "xsd:attribute": XsdAttribute[];
+  "@_name": string;
 }
 
 export interface XsdSequence {
@@ -61,7 +69,7 @@ export interface XsdSequence {
   };
 }
 
-export interface XSDExtension {
+export interface XsdExtension {
   "xsd:attribute"?: XsdAttribute[];
   "xsd:sequence"?: XsdSequence;
   "xsd:all"?: XsdAll;
@@ -72,7 +80,9 @@ export interface XSDExtension {
 export interface XsdComplexType {
   "@_name"?: string;
   "@_abstract"?: boolean;
+  "@_mixed"?: boolean;
   "xsd:attribute"?: XsdAttribute[];
+  "xsd:attributeGroup"?: Array<{ "@_ref": string }>;
   "xsd:sequence"?: XsdSequence;
   "xsd:all"?: XsdAll;
   "xsd:anyAttribute"?: {
@@ -80,10 +90,10 @@ export interface XsdComplexType {
     "@_processContents": "lax";
   };
   "xsd:complexContent"?: {
-    "xsd:extension"?: XSDExtension;
+    "xsd:extension"?: XsdExtension;
   };
   "xsd:simpleContent"?: {
-    "xsd:extension"?: XSDExtension;
+    "xsd:extension"?: XsdExtension;
   };
 }
 
@@ -121,7 +131,7 @@ export interface XsdTopLevelElement {
 }
 
 export interface XsdSchema {
-  "xsd:schema": {
+  "xsd:schema": XmlParserTsRootElementBaseType & {
     "@_targetNamespace": string;
     "@_elementFormDefault": "qualified";
     "@_attributeFormDefault": "unqualified";
@@ -130,5 +140,7 @@ export interface XsdSchema {
     "xsd:simpleType"?: XsdSimpleType[];
     "xsd:complexType"?: XsdComplexType[];
     "xsd:element"?: XsdTopLevelElement[];
+    "xsd:attribute"?: XsdAttribute[];
+    "xsd:attributeGroup"?: XsdTopLevelAttributeGroup[];
   };
 }
diff --git a/packages/xml-parser-ts-codegen/src/types.d.ts 
b/packages/xml-parser-ts-codegen/src/types.d.ts
index 669ff403f33..3375daf6c76 100644
--- a/packages/xml-parser-ts-codegen/src/types.d.ts
+++ b/packages/xml-parser-ts-codegen/src/types.d.ts
@@ -28,6 +28,7 @@ export type XptcComplexTypeBase = {
   isSimpleContent: boolean;
   needsExtensionType: boolean; // That's for sequences decalring 
<xsd:anyAttribute> or <xsd:any>
   declaredAtRelativeLocation: string;
+  attributes: XptcAttribute[];
   elements: Array<
     {
       isArray: boolean;
@@ -49,15 +50,11 @@ export type XptcComplexTypeBase = {
         }
     )
   >;
-  attributes: Array<{
-    name: string;
-    localTypeRef: string;
-    isOptional: boolean;
-  }>;
 };
 
 export type XptcComplexTypeAnonymous = XptcComplexTypeBase & {
   isAnonymous: true; // Declared directly inside elements.
+  isMixed: boolean;
   forElementWithName: string;
   parentIdentifierForExtensionType: string;
 };
@@ -65,11 +62,24 @@ export type XptcComplexTypeAnonymous = XptcComplexTypeBase 
& {
 export type XptcComplexTypeNamed = XptcComplexTypeBase & {
   name: string;
   isAbstract: boolean;
+  isMixed: boolean;
   isAnonymous: false;
 };
 
 export type XptcComplexType = XptcComplexTypeNamed | XptcComplexTypeAnonymous;
 
+export type XptcAttribute = {
+  name: string;
+  localTypeRef: string;
+  isOptional: boolean;
+  simpleType?: XptcSimpleType;
+};
+
+export type XptcTopLevelAttributeGroup = {
+  name: string;
+  attributes: XptcAttribute[];
+};
+
 export type XptcElement = {
   name: string;
   type?: string;
@@ -86,6 +96,9 @@ export type XptcSimpleType = {
   restrictionBase?: string;
   declaredAtRelativeLocation: string;
 } & (
+  | {
+      kind: "string";
+    }
   | {
       kind: "enum";
       values: string[];
diff --git a/packages/react-hooks/src/usePreviousRef.ts 
b/packages/xml-parser-ts/src/elementFilter.ts
similarity index 70%
copy from packages/react-hooks/src/usePreviousRef.ts
copy to packages/xml-parser-ts/src/elementFilter.ts
index b5855874e6a..1118a3e8ecb 100644
--- a/packages/react-hooks/src/usePreviousRef.ts
+++ b/packages/xml-parser-ts/src/elementFilter.ts
@@ -17,16 +17,14 @@
  * under the License.
  */
 
-import { useEffect, useRef } from "react";
+export type ElementFilter<E extends { __$$element: string }, Filter extends 
string> = E extends any
+  ? E["__$$element"] extends Filter
+    ? E
+    : never
+  : never;
 
-export function usePreviousRef<T>(value: T): React.MutableRefObject<T> {
-  const ref = useRef<T>(value);
-
-  useEffect(() => {
-    if (ref.current !== value) {
-      ref.current = value;
-    }
-  }, [value]);
-
-  return ref;
-}
+export type ElementExclusion<E extends { __$$element: string }, Filter extends 
string> = E extends any
+  ? E["__$$element"] extends Filter
+    ? never
+    : E
+  : never;
diff --git a/packages/xml-parser-ts/src/index.ts 
b/packages/xml-parser-ts/src/index.ts
index 8ade30121a3..76ca0fc0970 100644
--- a/packages/xml-parser-ts/src/index.ts
+++ b/packages/xml-parser-ts/src/index.ts
@@ -162,7 +162,7 @@ export function getParser<T extends object>(args: {
         if (k.endsWith(":") || k === "" /* Filters only `xmlns --> URL` 
mappings, since `ns` is bi-directional.*/) {
           const instanceNsKey = instanceNs.get(v)?.slice(0, -1);
           const originalXmlnsPropName = instanceNsKey ? 
`@_xmlns:${instanceNsKey}` : `@_xmlns`;
-          if (!instanceNsKey || 
!__json[args.root.element][originalXmlnsPropName]) {
+          if (instanceNsKey === undefined || 
!__json[args.root.element][originalXmlnsPropName]) {
             const nsName = k.slice(0, -1);
             const newXmlnsPropName = nsName ? `@_xmlns:${nsName}` : `@_xmlns`;
             console.warn(`Adding NS mapping to XML: ${newXmlnsPropName} --> 
${v}`);
@@ -181,6 +181,11 @@ export function getParser<T extends object>(args: {
         [args.root.element]: { type: args.root.type, fromType: "root", 
isArray: false, xsdType: "// root" },
       };
 
+      const declaredElementsOrder = [];
+      for (const e in args.elements ?? {}) {
+        declaredElementsOrder.push(e);
+      }
+
       const xml = build({
         json: __json,
         ns: args.ns,
@@ -188,6 +193,7 @@ export function getParser<T extends object>(args: {
         elements: args.elements,
         meta: args.meta,
         metaType: rootMetaType,
+        declaredElementsOrder,
         indent: "",
       });
       // console.timeEnd("building took");
@@ -216,7 +222,7 @@ export function parse(args: {
     const elemNode = children[ii];
 
     if (elemNode.nodeType === 1 /* ELEMENT_NODE */) {
-      const { nsedName, subsedName } = resolveElement(elemNode.nodeName, 
args.nodeMetaType, args);
+      const { nsedName, subsedName } = resolveQName(elemNode.nodeName, 
args.nodeMetaType, args);
 
       const elemMetaProp = args.nodeMetaType?.[subsedName ?? nsedName];
 
@@ -227,7 +233,8 @@ export function parse(args: {
           : undefined); // If the current element is not known, we simply 
ignore its type and go with the defaults.
 
       // If the elemNode's meta type has a __$$text property, this is the one 
we use to parse its value.
-      // All other properties on `elemType` are certainly attributes, which 
are handlded below.
+      // All other properties (except `__$$element`) on `elemType` are 
certainly attributes, which are handled below.
+      // The `__$$element` property is also processed below, since there can 
be an element with both `__$$text` and `__$$element` properties.
       const t = elemMetaType?.["__$$text"]?.type ?? elemMetaProp?.type;
 
       let elemValue: any = {};
@@ -241,16 +248,27 @@ export function parse(args: {
         elemValue["__$$text"] = parseFloat(elemNode.textContent ?? "");
       } else {
         elemValue = parse({ ...args, node: elemNode, nodeMetaType: 
elemMetaType });
-        if (subsedName !== nsedName) {
-          // substitution occurred, need to save the original, normalized 
element name
-          elemValue["__$$element"] = nsedName;
-        }
       }
 
+      if (subsedName !== nsedName) {
+        // substitution occurred, need to save the original, normalized 
element name
+        elemValue["__$$element"] = nsedName;
+      }
+
+      const argsForAttrs = { ns: args.ns, instanceNs: args.instanceNs, subs: 
{} }; // Attributes can't use substitution groups.
       const attrs = (elemNode as Element).attributes;
       for (let i = 0; i < attrs.length; i++) {
         const attr = attrs[i];
-        const attrPropType = elemMetaType?.[`@_${attr.name}`];
+        const resolvedAttrQName = resolveQName(attr.name, args.nodeMetaType, 
argsForAttrs);
+
+        // If the attribute's name is not qualified, we don't mess
+        // with it. We treat it as having no namespace, instead of
+        // potentially using the default namespace mapped with `xmlns=`.
+        const attrName = resolvedAttrQName.isQualified
+          ? resolvedAttrQName.subsedName ?? resolvedAttrQName.nsedName
+          : attr.name;
+
+        const attrPropType = elemMetaType?.[`@_${attrName}`];
 
         let attrValue: any;
         if (attrPropType?.type === "string") {
@@ -267,7 +285,7 @@ export function parse(args: {
           attrValue = attr.value; // Unknown type, default to the text from 
the XML.
         }
 
-        elemValue[`@_${attr.name}`] = attrValue;
+        elemValue[`@_${attrName}`] = attrValue;
       }
 
       const currentValue = json[subsedName ?? nsedName];
@@ -296,7 +314,7 @@ export function parse(args: {
   return json;
 }
 
-export function resolveElement(
+export function resolveQName(
   name: string,
   parentMetaType: MetaType | undefined,
   {
@@ -311,14 +329,17 @@ export function resolveElement(
 ) {
   let nameNs = undefined;
   let nameName = undefined;
+  let isQualified: boolean;
 
   const s = name.split(":");
   if (s.length === 1) {
     nameNs = ns.get(instanceNs.get("")!) ?? "";
     nameName = s[0];
+    isQualified = false;
   } else if (s.length === 2) {
     nameNs = ns.get(instanceNs.get(`${s[0]}:`)!) ?? `${s[0]}:`;
     nameName = s[1];
+    isQualified = true;
   } else {
     throw new Error(name);
   }
@@ -339,7 +360,7 @@ export function resolveElement(
     subsedName = nsedSubs[subsedName];
   }
 
-  return { nsedName, subsedName };
+  return { nsedName, subsedName, isQualified };
 }
 
 function parseInt(attrValue: string) {
@@ -410,7 +431,7 @@ function applyEntities(value: any) {
     .replace(quotEntity.regex, quotEntity.replacement);
 }
 
-function buildAttrs(json: any) {
+function buildAttrs(json: any, { ns, instanceNs }: { ns: Map<string, string>; 
instanceNs: Map<string, string> }) {
   let isEmpty = true;
   let hasText = false;
   let attrs = " ";
@@ -418,7 +439,12 @@ function buildAttrs(json: any) {
   // Attributes don't ever need to be serialized in a particular order.
   for (const propName in json) {
     if (propName[0] === "@") {
-      attrs += `${propName.substring(2)}="${applyEntities(json[propName])}" `;
+      const attrName =
+        propName.split(":").length === 2 // only apply namespace if it's 
qualified name. attributes are unnamespaced by default.
+          ? applyInstanceNs({ propName: propName.substring(2), instanceNs, ns 
})
+          : propName.substring(2);
+
+      attrs += `${attrName}="${applyEntities(json[propName])}" `;
     } else if (propName === "__$$text") {
       hasText = true;
       isEmpty = false;
@@ -441,6 +467,7 @@ export function build(args: {
   elements: Elements;
   meta: Meta;
   metaType: MetaType | undefined;
+  declaredElementsOrder: string[];
   indent: string;
 }): string {
   const { json, ns, instanceNs, indent, metaType } = args;
@@ -451,7 +478,7 @@ export function build(args: {
 
   let xml = "";
 
-  // We want to respect a certain order here given xsd:sequence declarations.
+  // We want to respect a certain order here given xsd:sequence, xsd:choice, 
and xsd:all declarations
   const sortedJsonProps: string[] = [];
   for (const p in json) {
     sortedJsonProps.push(p);
@@ -483,7 +510,7 @@ export function build(args: {
     }
     // pi tag
     else if (jsonPropName[0] === "?") {
-      xml = `${indent}<${jsonPropName}${buildAttrs(jsonPropValue).attrs} ?>\n` 
+ xml; // PI Tags should always go at the top of the XML
+      xml = `${indent}<${jsonPropName}${buildAttrs(jsonPropValue, args).attrs} 
?>\n` + xml; // PI Tags should always go at the top of the XML
     }
     // empty tag
     else if (jsonPropValue === undefined || jsonPropValue === null || 
jsonPropValue === "") {
@@ -497,9 +524,17 @@ export function build(args: {
     }
     // array
     else if (Array.isArray(jsonPropValue)) {
-      for (const item of jsonPropValue) {
+      // In order to keep the order of elements of xsd:sequences in a 
`substituionGroup`
+      // we need to sort elements by their declaration order.
+      const elemOrder = args.declaredElementsOrder;
+      const arr =
+        jsonPropValue?.[0]?.__$$element === undefined
+          ? jsonPropValue
+          : jsonPropValue.toSorted((a, b) => elemOrder.indexOf(a.__$$element) 
- elemOrder.indexOf(b.__$$element));
+
+      for (const item of arr) {
         const elementName = applyInstanceNs({ ns, instanceNs, propName: 
item?.["__$$element"] ?? jsonPropName });
-        const { attrs, isEmpty, hasText } = buildAttrs(item);
+        const { attrs, isEmpty, hasText } = buildAttrs(item, args);
         xml += `${indent}<${elementName}${attrs}`;
         if (isEmpty) {
           xml += " />\n";
@@ -522,7 +557,7 @@ export function build(args: {
     else {
       const item = jsonPropValue;
       const elementName = applyInstanceNs({ ns, instanceNs, propName: 
item["__$$element"] ?? jsonPropName });
-      const { attrs, isEmpty, hasText } = buildAttrs(item);
+      const { attrs, isEmpty, hasText } = buildAttrs(item, args);
       xml += `${indent}<${elementName}${attrs}`;
       if (isEmpty) {
         xml += " />\n";


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to