[ https://issues.apache.org/jira/browse/XMLBEANS-637?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17727393#comment-17727393 ]
Ronan edited comment on XMLBEANS-637 at 5/30/23 8:27 AM: --------------------------------------------------------- To solve this issue, I inherit and overwrite the method *_processElementsInComplexType()_* to add one more condition to check the same contiguous elements. I create a new class CustomRussianDollStrategy as below. My newly added condition is {code:java} equals(currentElem.getName(), child.getName()) {code} {code:java} public class CustomRussianDollStrategy extends RussianDollStrategy implements XsdGenStrategy { private static final ILogger logger = LoggerFactory.getLogger(CustomRussianDollStrategy.class); public CustomRussianDollStrategy() { //do nothing here } @Override protected void processElementsInComplexType(Type elemType, List children, String parentNamespace, TypeSystemHolder typeSystemHolder, Inst2XsdOptions options) { Map elemNamesToElements = new HashMap(); Element currentElem = null; Iterator iterator = children.iterator(); while(iterator.hasNext()) { Element child = (Element) iterator.next(); if (currentElem==null) { // first element in this type checkIfElementReferenceIsNeeded(child, parentNamespace, typeSystemHolder, options); elemType.addElement(child); elemNamesToElements.put(child.getName(), child); currentElem = child; logger.debug("First element, currentElem:: " + currentElem); } else if (currentElem.getName() == child.getName() || equals(currentElem.getName(), child.getName())) { // same contiguous element combineTypes(currentElem.getType(), child.getType(), options); // unify types combineElementComments(currentElem, child); // minOcc=0 maxOcc=unbounded currentElem.setMinOccurs(0); currentElem.setMaxOccurs(Element.UNBOUNDED); String msg = "CombineType of same contiguous elements" +"\n - currentElem:: " + currentElem +"\n - child:: " + child; logger.debug(msg); } else { Element sameElem = (Element)elemNamesToElements.get(child.getName()); if (sameElem==null) { // new element name checkIfElementReferenceIsNeeded(child, parentNamespace, typeSystemHolder, options); elemType.addElement(child); elemNamesToElements.put(child.getName(), child); logger.debug("Combine new element, child:: " + child); } else { //same non contiguos combineTypes(currentElem.getType(), child.getType(), options); combineElementComments(currentElem, child); elemType.setTopParticleForComplexOrMixedContent(Type.PARTICLE_CHOICE_UNBOUNDED); String msg = "CombineType of same non-contiguous elements" +"\n - currentElem:: " + currentElem +"\n - child:: " + child; logger.debug(msg); } currentElem = child; } } } private static boolean equals(QName prevObj, QName nextObj) { return prevObj.getLocalPart().equals(nextObj.getLocalPart()) && prevObj.getNamespaceURI().equals(nextObj.getNamespaceURI()) && prevObj.getPrefix().equals(nextObj.getPrefix()); } } {code} In the final step, I create another class _*CustomInst2Xsd*_ to create the instance of the _*CustomRussianDollStrategy*_ class. {code:java} public class CustomInst2Xsd { private static final ILogger logger = LoggerFactory.getLogger(CustomInst2Xsd.class); private CustomInst2Xsd() {} public static SchemaDocument[] inst2xsd(XmlObject[] instances, Inst2XsdOptions options) { XsdGenStrategy strategy; if (options == null) options = new Inst2XsdOptions(); TypeSystemHolder typeSystemHolder = new TypeSystemHolder(); switch (options.getDesign()) { case Inst2XsdOptions.DESIGN_RUSSIAN_DOLL: strategy = new CustomRussianDollStrategy(); break; case Inst2XsdOptions.DESIGN_SALAMI_SLICE: strategy = new SalamiSliceStrategy(); break; case Inst2XsdOptions.DESIGN_VENETIAN_BLIND: strategy = new VenetianBlindStrategy(); break; default: throw new IllegalArgumentException("Unknown design."); } strategy.processDoc(instances, options, typeSystemHolder); return typeSystemHolder.getSchemaDocuments(); } }{code} Hopefully, the official fix for the bug will be included in a future release. was (Author: JIRAUSER300632): To solve this issue, I inherit and overwrite the method *_processElementsInComplexType()_* to add one more condition to check the same contiguous elements. I create a new class CustomRussianDollStrategy as below. My newly added condition is {code:java} equals(currentElem.getName(), child.getName()) {code} {code:java} public class CustomRussianDollStrategy extends RussianDollStrategy implements XsdGenStrategy { private static final ILogger logger = LoggerFactory.getLogger(CustomRussianDollStrategy.class); public CustomRussianDollStrategy() { //do nothing here } @Override protected void processElementsInComplexType(Type elemType, List children, String parentNamespace, TypeSystemHolder typeSystemHolder, Inst2XsdOptions options) { Map elemNamesToElements = new HashMap(); Element currentElem = null; Iterator iterator = children.iterator(); while(iterator.hasNext()) { Element child = (Element) iterator.next(); if (currentElem==null) { // first element in this type checkIfElementReferenceIsNeeded(child, parentNamespace, typeSystemHolder, options); elemType.addElement(child); elemNamesToElements.put(child.getName(), child); currentElem = child; logger.debug("First element, currentElem:: " + currentElem); } else if (currentElem.getName() == child.getName() || equals(currentElem.getName(), child.getName())) { // same contiguous element combineTypes(currentElem.getType(), child.getType(), options); // unify types combineElementComments(currentElem, child); // minOcc=0 maxOcc=unbounded currentElem.setMinOccurs(0); currentElem.setMaxOccurs(Element.UNBOUNDED); String msg = "CombineType of same contiguous elements" +"\n - currentElem:: " + currentElem +"\n - child:: " + child; logger.debug(msg); } else { Element sameElem = (Element)elemNamesToElements.get(child.getName()); if (sameElem==null) { // new element name checkIfElementReferenceIsNeeded(child, parentNamespace, typeSystemHolder, options); elemType.addElement(child); elemNamesToElements.put(child.getName(), child); logger.debug("Combine new element, child:: " + child); } else { //same non contiguos combineTypes(currentElem.getType(), child.getType(), options); combineElementComments(currentElem, child); elemType.setTopParticleForComplexOrMixedContent(Type.PARTICLE_CHOICE_UNBOUNDED); String msg = "CombineType of same non-contiguous elements" +"\n - currentElem:: " + currentElem +"\n - child:: " + child; logger.debug(msg); } currentElem = child; } } } private static boolean equals(QName prevObj, QName nextObj) { return prevObj.getLocalPart().equals(nextObj.getLocalPart()) && prevObj.getNamespaceURI().equals(nextObj.getNamespaceURI()) && prevObj.getPrefix().equals(nextObj.getPrefix()); } } {code} In the final step, I create another class _*CustomInst2Xsd*_ to create the instance of the _*CustomRussianDollStrategy*_ class. {code:java} public class CustomInst2Xsd { private static final ILogger logger = LoggerFactory.getLogger(CustomInst2Xsd.class); private CustomInst2Xsd() {} public static SchemaDocument[] inst2xsd(XmlObject[] instances, Inst2XsdOptions options) { XsdGenStrategy strategy; if (options == null) options = new Inst2XsdOptions(); TypeSystemHolder typeSystemHolder = new TypeSystemHolder(); switch (options.getDesign()) { case Inst2XsdOptions.DESIGN_RUSSIAN_DOLL: strategy = new CustomRussianDollStrategy(); break; case Inst2XsdOptions.DESIGN_SALAMI_SLICE: strategy = new SalamiSliceStrategy(); break; case Inst2XsdOptions.DESIGN_VENETIAN_BLIND: strategy = new VenetianBlindStrategy(); break; default: throw new IllegalArgumentException("Unknown design."); } strategy.processDoc(instances, options, typeSystemHolder); return typeSystemHolder.getSchemaDocuments(); } }{code} > Combine same contiguous element types incorrectly while generating XSD from > an XML instance > ------------------------------------------------------------------------------------------- > > Key: XMLBEANS-637 > URL: https://issues.apache.org/jira/browse/XMLBEANS-637 > Project: XMLBeans > Issue Type: Bug > Components: Cursor > Affects Versions: Version 3.0.1, Version 5.1.0 > Reporter: Ronan > Priority: Major > Fix For: unspecified > > Attachments: image-2023-05-30-15-00-38-785.png, > image-2023-05-30-15-09-05-151.png > > > h2. Step to reproduce > 1- Using this given XML instance to generate an XSD schema with XMLBeans > v5.1.0 (or v3.0.1). Please note that there are two contiguous *<Result>* > nodes in the XML document. > {code:java} > <data> > <Code>6065</Code> > <LocNum>6065</LocNum> > <StockNum>23123191</StockNum> > <Vin>1C4NJRFB4GD618747</Vin> > <YearCode>g</YearCode> > <MakeCode>JE</MakeCode> > <ModelCode>PATR</ModelCode> > <TrimCode>HIAL</TrimCode> > <BodyCode>S006</BodyCode> > <EngineCode>0024</EngineCode> > <FuelType>G</FuelType> > <TransCode>A</TransCode> > <ClassCode>80</ClassCode> > <Color>100</Color> > <IntColor>2392</IntColor> > <PrevProdStatus>525</PrevProdStatus> > <ProdStatus>520</ProdStatus> > <Mileage>33333</Mileage> > <LastLotDate>2022-12-12T05:12:53.826-04:00</LastLotDate> > <LastLotAssign>LB5</LastLotAssign> > <Result> > <child-result>test1</child-result> > </Result> > <Result> > <child-result>test2</child-result> > </Result> > </data> {code} > > 2- Try using this snippet code to generate the XSD schema from the above XML > instance > {code:java} > public static void main(String[] args) { > try { > XmlObject[] xmlInstances = new XmlObject[1]; > xmlInstances[0] = XmlObject.Factory.parse(new > String(Files.readAllBytes(Paths.get("path_to_the_xml_file")))); > Inst2XsdOptions inst2XsdOptions = new Inst2XsdOptions(); > inst2XsdOptions.setDesign(Inst2XsdOptions.DESIGN_RUSSIAN_DOLL); > inst2XsdOptions.setUseEnumerations(Inst2XsdOptions.ENUMERATION_NEVER); > > inst2XsdOptions.setSimpleContentTypes(Inst2XsdOptions.SIMPLE_CONTENT_TYPES_SMART); > SchemaDocument[] schemaDocuments = Inst2Xsd.inst2xsd(xmlInstances, > inst2XsdOptions); > if (schemaDocuments != null && schemaDocuments.length > 0) { > System.out.println(schemaDocuments[0].toString()); > } > } catch (Exception e) { > e.printStackTrace(); > } > } {code} > h2. Expected Result: > In the output XSD schema, the element *Result* should be an array > _(maxOccurs="unbounded" minOccurs="0")_ > {code:java} > <schema attributeFormDefault="unqualified" elementFormDefault="qualified" > xmlns="http://www.w3.org/2001/XMLSchema"> > <element name="data"> > <complexType> > <sequence> > <element type="xs:short" name="Code" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:short" name="LocNum" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:int" name="StockNum" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:string" name="Vin" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:string" name="YearCode" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:string" name="MakeCode" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:string" name="ModelCode" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:string" name="TrimCode" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:string" name="BodyCode" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:byte" name="EngineCode" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:string" name="FuelType" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:string" name="TransCode" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:byte" name="ClassCode" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:byte" name="Color" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:short" name="IntColor" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:short" name="PrevProdStatus" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:short" name="ProdStatus" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:int" name="Mileage" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:dateTime" name="LastLotDate" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:string" name="LastLotAssign" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element name="Result" maxOccurs="unbounded" minOccurs="0"> > <complexType> > <sequence> > <element type="xs:string" name="child-result" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > </sequence> > </complexType> > </element> > </sequence> > </complexType> > </element> > </schema>{code} > h2. Actual Result: > The element Result is not an array. > {code:java} > <schema attributeFormDefault="unqualified" elementFormDefault="qualified" > xmlns="http://www.w3.org/2001/XMLSchema"> > <element name="data"> > <complexType> > <choice maxOccurs="unbounded" minOccurs="0"> > <element type="xs:short" name="Code" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:short" name="LocNum" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:int" name="StockNum" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:string" name="Vin" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:string" name="YearCode" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:string" name="MakeCode" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:string" name="ModelCode" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:string" name="TrimCode" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:string" name="BodyCode" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:byte" name="EngineCode" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:string" name="FuelType" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:string" name="TransCode" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:byte" name="ClassCode" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:byte" name="Color" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:short" name="IntColor" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:short" name="PrevProdStatus" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:short" name="ProdStatus" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:int" name="Mileage" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:dateTime" name="LastLotDate" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element type="xs:string" name="LastLotAssign" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > <element name="Result"> > <complexType> > <sequence> > <element type="xs:string" name="child-result" > xmlns:xs="http://www.w3.org/2001/XMLSchema"/> > </sequence> > </complexType> > </element> > </choice> > </complexType> > </element> > </schema>{code} > ---- > h2. My Investigating Info > Below is information I found while looking for the answer to why this happens. > > While parsing the input XML instance and calling _*getName()*_ method in > {_}QNameCache.class{_}, the first *Result* node is added to the table right > before the table's size reaches the threshold. The first *Result* node is > allocated to a new memory address as the attached image. > Then, the class executes the *_rehash()_* method to increase the size of the > table to receive more incoming nodes. > Next, the last *Result* node is added to the table, but it is allocated to a > separate memory address instead of referring to the first *Result* node > (please note that their URI, localName, and prefix are exactly the same ) > !image-2023-05-30-15-00-38-785.png! > > After that, in {_}RussianDollStrategy.class{_}, the method > *_processElementsInComplexType()_* compares those two *Result* QName by using > the *==* operator to check if they are the same contiguous elements. > The == operator checks whether objects are identical or not. In this case, it > returns false as those two *Result* QName objects are located in different > memory addresses, and the consequence is it does not combine the element type. > > I think this case should be covered by adding one more condition to compare > their namespaceURI, localPart, and prefix. > {code:java} > else if (currentElem.getName() == child.getName() || > currentElem.getName().equals(child.getName()) {code} > !image-2023-05-30-15-09-05-151.png! > > > > > -- This message was sent by Atlassian Jira (v8.20.10#820010) --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@poi.apache.org For additional commands, e-mail: dev-h...@poi.apache.org