6666import org .frankframework .frankdoc .model .TextConfigChild ;
6767import org .frankframework .frankdoc .util .LogUtil ;
6868import org .frankframework .frankdoc .util .XmlBuilder ;
69+ import org .frankframework .frankdoc .wrapper .AdditionalRootElement ;
6970
7071/**
7172 * This class writes the XML schema document (XSD) that checks the validity of a
@@ -167,6 +168,11 @@ public class FrankDocXsdFactory implements AttributeReuseManagerCallback {
167168 private final Set <String > definedAttributeEnumInstances = new HashSet <>();
168169 private final AttributeTypeStrategy attributeTypeStrategy ;
169170 private final String frankFrameworkVersion ;
171+ /**
172+ * Map {@link AdditionalRootElement} enum values for Frank!Framework Java types that have been encountered to the XSD types
173+ * that they map to.
174+ */
175+ private final Map <AdditionalRootElement , String > additionalRootElements = new EnumMap <>(AdditionalRootElement .class );
170176
171177 public FrankDocXsdFactory (FrankDocModel model , AttributeTypeStrategy attributeTypeStrategy , String frankFrameworkVersion , String startClassName , XsdVersion version ) {
172178 this .model = model ;
@@ -230,6 +236,7 @@ private void defineElements(FrankElement startElement) {
230236 default :
231237 throw new IllegalArgumentException ("Cannot happen - all case labels should be in switch" );
232238 }
239+ additionalRootElements .forEach (this ::createAdditionalRootElement );
233240 }
234241
235242 /** Defines XML element {@code <Configuration>} */
@@ -261,6 +268,26 @@ private void addReferencedEntityRoot(FrankElement startElement) {
261268 attributeReuseManager .addAttribute (anyOther , complexType );
262269 }
263270
271+ /**
272+ * Defines XML element {@code <PipelinePart/>} or other additional root elements
273+ */
274+ private void createAdditionalRootElement (AdditionalRootElement additionalRootElement , String referencedElementGroupName ) {
275+ String elementName = additionalRootElement .getElementName ();
276+ log .trace ("Creating element [{}]" , elementName );
277+ XmlBuilder startElementBuilder = createElementWithName (elementName );
278+ xsdElements .add (startElementBuilder );
279+ addDocumentation (startElementBuilder , additionalRootElement .getDocString ());
280+ XmlBuilder complexType = addComplexType (startElementBuilder );
281+ XmlBuilder sequence = addSequence (complexType );
282+ FrankDocXsdFactoryXmlUtils .addGroupRef (sequence , referencedElementGroupName , "0" , "unbounded" );
283+
284+ log .trace ("Adding attribute active explicitly to [{}] and also any attribute in another namespace" , elementName );
285+ XmlBuilder attributeActive = AttributeTypeStrategy .createAttributeActive ();
286+ attributeReuseManager .addAttribute (attributeActive , complexType );
287+ XmlBuilder anyOther = createAnyOtherNamespaceAttribute ();
288+ attributeReuseManager .addAttribute (anyOther , complexType );
289+ }
290+
264291 private String getConfigChildGroupOf (FrankElement frankElement ) {
265292 // TODO: Add cumulative group if the start element (typically <Configuration>) has
266293 // ancestors with config children. Or even take a declared/cumulative group of an ancestor
@@ -521,7 +548,7 @@ private void addConfigChildren(ElementBuildingStrategy elementBuildingStrategy,
521548 private void addConfigChildrenNoPluralConfigChildSets (ElementBuildingStrategy elementBuildingStrategy , FrankElement frankElement ) {
522549 Consumer <GroupCreator .Callback <ConfigChild >> cumulativeGroupTrigger =
523550 ca -> frankElement .walkCumulativeConfigChildren (ca , version .getChildSelector (), version .getChildRejector ());
524- new GroupCreator <ConfigChild >(frankElement , version .getHasRelevantChildrenPredicate (ConfigChild .class ), cumulativeGroupTrigger , new GroupCreator .Callback <ConfigChild >() {
551+ new GroupCreator <>(frankElement , version .getHasRelevantChildrenPredicate (ConfigChild .class ), cumulativeGroupTrigger , new GroupCreator .Callback <>() {
525552 private XmlBuilder cumulativeBuilder ;
526553 private String cumulativeGroupName ;
527554
@@ -618,12 +645,7 @@ private void addObjectConfigChild(XmlBuilder context, ObjectConfigChild child) {
618645
619646 private boolean isNoElementTypeNeeded (ElementRole role ) {
620647 ElementType elementType = role .getElementType ();
621- if (elementType .isFromJavaInterface ()) {
622- return false ;
623- }
624- else {
625- return true ;
626- }
648+ return !elementType .isFromJavaInterface ();
627649 }
628650
629651 private void addConfigChildSingleReferredElement (XmlBuilder context , ObjectConfigChild child ) {
@@ -633,6 +655,7 @@ private void addConfigChildSingleReferredElement(XmlBuilder context, ObjectConfi
633655 log .trace ("Omitting config child [{}] because of name conflict" , child ::toString );
634656 return ;
635657 }
658+
636659 String referredXsdElementName = elementInType .getXsdElementName (role );
637660 log .trace ("Config child appears as element reference to FrankElement [{}], XSD element [{}]" , elementInType ::getFullName , () -> referredXsdElementName );
638661 addElement (context , referredXsdElementName , getTypeName (referredXsdElementName ), getMinOccurs (child ), getMaxOccurs (child ));
@@ -707,6 +730,15 @@ private void requestElementGroup(List<ElementRole> roles) {
707730 XmlBuilder choice = addChoice (group );
708731 addElementGroupGenericOption (choice , roles );
709732 addElementGroupOptions (choice , roles );
733+ String elementTypeSimpleName = key .iterator ().next ().getElementTypeSimpleName ();
734+
735+ // The "Include" element should be manually added to the XSD as part of the "xs:choice" for this element-group.
736+ // We cannot have it added in a simpler way from the Frank!Framework code, as it will then not be valid as
737+ // part of the choice of elements in this element-group, but as a separate group of elements.
738+ if (model .shouldGetIncludeElement (elementTypeSimpleName )) {
739+ addElement (choice , "Include" , "IncludeType" , "0" , "unbounded" );
740+ additionalRootElements .put (model .getAdditionalRootElement (elementTypeSimpleName ), groupName );
741+ }
710742 } else {
711743 log .trace ("Element group already exists" );
712744 }
@@ -734,7 +766,8 @@ private void addElementGroupOptions(XmlBuilder context, List<ElementRole> roles)
734766 }
735767
736768 private void defineElementGroupBaseUnchecked (ElementRole role ) {
737- XmlBuilder group = createGroup (role .createXsdElementName (ELEMENT_GROUP_BASE ));
769+ String groupName = role .createXsdElementName (ELEMENT_GROUP_BASE );
770+ XmlBuilder group = createGroup (groupName );
738771 xsdComplexItems .add (group );
739772 XmlBuilder choice = addChoice (group );
740773 List <FrankElement > frankElementOptions = role .getMembers ().stream ()
0 commit comments