Package org.eclipse.sapphire.sdk.xml.schema.normalizer.internal

Source Code of org.eclipse.sapphire.sdk.xml.schema.normalizer.internal.CreateNormalizedXmlSchemaOpMethods$ElementChildrenComparator

/******************************************************************************
* Copyright (c) 2014 Oracle
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*    Konstantin Komissarchik - initial implementation
******************************************************************************/

package org.eclipse.sapphire.sdk.xml.schema.normalizer.internal;

import static org.eclipse.sapphire.modeling.util.MiscUtil.equal;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.sapphire.LocalizableText;
import org.eclipse.sapphire.PropertyVisitor;
import org.eclipse.sapphire.Text;
import org.eclipse.sapphire.Value;
import org.eclipse.sapphire.modeling.ByteArrayResourceStore;
import org.eclipse.sapphire.modeling.FileResourceStore;
import org.eclipse.sapphire.modeling.Path;
import org.eclipse.sapphire.modeling.ProgressMonitor;
import org.eclipse.sapphire.modeling.ResourceStoreException;
import org.eclipse.sapphire.modeling.Status;
import org.eclipse.sapphire.modeling.UrlResourceStore;
import org.eclipse.sapphire.modeling.xml.XmlAttribute;
import org.eclipse.sapphire.modeling.xml.XmlComment;
import org.eclipse.sapphire.modeling.xml.XmlElement;
import org.eclipse.sapphire.modeling.xml.XmlResourceStore;
import org.eclipse.sapphire.platform.PathBridge;
import org.eclipse.sapphire.platform.StatusBridge;
import org.eclipse.sapphire.sdk.xml.schema.normalizer.CreateNormalizedXmlSchemaOp;
import org.eclipse.sapphire.sdk.xml.schema.normalizer.CreateNormalizedXmlSchemaOp.Exclusion;
import org.eclipse.sapphire.sdk.xml.schema.normalizer.CreateNormalizedXmlSchemaOp.Exclusion.ExclusionType;
import org.eclipse.sapphire.sdk.xml.schema.normalizer.CreateNormalizedXmlSchemaOp.TypeSubstitution;
import org.eclipse.sapphire.util.SetFactory;
import org.eclipse.sapphire.workspace.WorkspaceFileResourceStore;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
* @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a>
*/

public final class CreateNormalizedXmlSchemaOpMethods
{
    private static final String NS_SCHEMA = "http://www.w3.org/2001/XMLSchema";

    @Text( "Creating normalized XML schema file..." )
    private static LocalizableText executeTaskName;
   
    static
    {
        LocalizableText.init( CreateNormalizedXmlSchemaOpMethods.class );
    }

    public static Status execute( final CreateNormalizedXmlSchemaOp operation,
                                  ProgressMonitor monitor )
    {
        if( monitor == null )
        {
            monitor = new ProgressMonitor();
        }
       
        monitor.beginTask( executeTaskName.text(), 2 );
       
        try
        {
            final Path sourceSchemaFilePath = operation.getSourceFile().content();
           
            final PersistedState state = PersistedStateManager.load( sourceSchemaFilePath );
           
            if( state != null )
            {
                try
                {
                    state.getRootElements().copy( operation );
                    state.getExclusions().copy( operation );
                    state.getTypeSubstitutions().copy( operation );
                    state.getSortSequenceContent().copy( operation );
                    state.getRemoveWildcards().copy( operation );
                    state.resource().save();
                }
                catch( ResourceStoreException e )
                {
                    // Ignore, since persisted state isn't a critical aspect.
                }
                finally
                {
                    state.dispose();
                }
            }
           
            final IWorkspaceRoot wsroot = ResourcesPlugin.getWorkspace().getRoot();
            final IFile sourceSchemaFile = wsroot.getFile( PathBridge.create( sourceSchemaFilePath ) );
            final IFile targetSchemaFile = operation.getFile().target();
           
            try
            {
                final InputStream sourceSchemaFileInputStream = sourceSchemaFile.getContents();
               
                try
                {
                    targetSchemaFile.refreshLocal( IResource.DEPTH_ZERO, new NullProgressMonitor() );
                   
                    create( targetSchemaFile.getParent() );
                   
                    if( targetSchemaFile.exists() )
                    {
                        targetSchemaFile.setContents( sourceSchemaFileInputStream, IFile.FORCE, null );
                    }
                    else
                    {
                        targetSchemaFile.create( sourceSchemaFileInputStream, IFile.FORCE, null );
                    }
                }
                finally
                {
                    try
                    {
                        sourceSchemaFileInputStream.close();
                    }
                    catch( IOException e ) {}
                }
            }
            catch( CoreException e )
            {
                return StatusBridge.create( e.getStatus() );
            }
           
            monitor.worked( 1 );
           
            try
            {
                final WorkspaceFileResourceStore fileResourceStore = new WorkspaceFileResourceStore( targetSchemaFile );
                final XmlResourceStore xmlResourceStore = new XmlResourceStore( fileResourceStore );
                final XmlElement root = new XmlElement( xmlResourceStore, xmlResourceStore.getDomDocument().getDocumentElement() );
               
                final String targetNamespace = root.getAttributeText( "targetNamespace" );
                String targetNamespacePrefix = null;
               
                for( XmlAttribute attribute : root.getAttributes() )
                {
                    final String name = attribute.getDomNode().getName();
                    final String value = attribute.getText();
                   
                    if( name.startsWith( "xmlns:" ) && value.equals( targetNamespace ) )
                    {
                        targetNamespacePrefix = name.substring( 6 );
                    }
                }
   
                final Set<String> included = new HashSet<String>();
                included.add( sourceSchemaFile.getLocation().toOSString() );
                while( inlineIncludes( root, sourceSchemaFile.getParent().getLocation().toOSString(), included ) );
               
                removeComments( root );
                removeAnnotations( root );
                removeDefaultMinMaxOccurs( root );
               
                if( operation.getRemoveWildcards().content() )
                {
                    removeWildcards( root );
                }
               
                exclude( root, operation.getExclusions() );
               
                final Map<String,XmlElement> types = new HashMap<String,XmlElement>();
                final Map<String,XmlElement> elements = new HashMap<String,XmlElement>();
                final Map<String,XmlElement> groups = new HashMap<String,XmlElement>();
               
                for( XmlElement element : root.getChildElements() )
                {
                    final String elname = element.getLocalName();
                   
                    if( elname.equals( "simpleType" ) || elname.equals( "complexType" ) )
                    {
                        String tname = element.getAttributeText( "name" );
                       
                        if( tname.length() > 0 )
                        {
                            if( targetNamespacePrefix != null )
                            {
                                tname = targetNamespacePrefix + ":" + tname;
                            }
                           
                            if( types.containsKey( tname ) )
                            {
                                element.remove();
                            }
                            else
                            {
                                types.put( tname, element );
                            }
                        }
                    }
                    else if( elname.equals( "element" ) )
                    {
                        String ename = element.getAttributeText( "name" );
                       
                        if( ename.length() > 0 )
                        {
                            if( targetNamespacePrefix != null )
                            {
                                ename = targetNamespacePrefix + ":" + ename;
                            }
                           
                            if( elements.containsKey( ename ) )
                            {
                                element.remove();
                            }
                            else
                            {
                                elements.put( ename, element );
                            }
                        }
                    }
                    else if( elname.equals( "group" ) )
                    {
                        String gname = element.getAttributeText( "name" );
                       
                        if( gname.length() > 0 )
                        {
                            if( targetNamespacePrefix != null )
                            {
                                gname = targetNamespacePrefix + ":" + gname;
                            }
                           
                            if( groups.containsKey( gname ) )
                            {
                                element.remove();
                            }
                            else
                            {
                                groups.put( gname, element );
                            }
                        }
                    }
                }
               
                changeSchemaNamespacePrefix( root.getDomNode().getOwnerDocument(), "xsd" );
               
                final Map<String,String> typeSubstitutions = new HashMap<String,String>();
               
                for( TypeSubstitution sub : operation.getTypeSubstitutions() )
                {
                    typeSubstitutions.put( sub.getBefore().content(), sub.getAfter().content() );
                }
               
                applyTypeSubstitutions( root, typeSubstitutions );
               
                boolean keepInlining = true;
               
                while( keepInlining )
                {
                    keepInlining =
                        inlineRestriction( root )
                        || inlineExtension( root )
                        || inlineSequenceInSequence( root )
                        || inlineSequenceInChoice( root )
                        || inlineTypes( root, types, SetFactory.<String>empty() )
                        || inlineElements( root, elements, SetFactory.<String>empty() )
                        || inlineGroups( root, groups, SetFactory.<String>empty() )
                        || removeRedundantMinMaxOccursInChoice( root );
                }
               
                for( XmlElement element : root.getChildElements() )
                {
                    final String elname = element.getLocalName();
                   
                    if( elname.equals( "simpleType" ) || elname.equals( "complexType" ) || elname.equals( "group" ) )
                    {
                        element.remove();
                    }
                }
               
                // If root elements are specified, remove all other top-level elements.
               
                if( ! operation.getRootElements().empty() )
                {
                    final SetFactory<String> rootsFactory = SetFactory.start();
                   
                    operation.visit
                    (
                        "RootElements/Name",
                        new PropertyVisitor()
                        {
                            @Override
                            public boolean visit( final Value<?> property )
                            {
                                rootsFactory.add( property.text() );
                                return true;
                            }
                        }
                    );
                   
                    final Set<String> roots = rootsFactory.result();
                           
                    for( XmlElement element : root.getChildElements() )
                    {
                        final String elname = element.getLocalName();
                       
                        if( elname.equals( "element" ) && ! roots.contains( element.getAttributeText( "name" ) ) )
                        {
                            element.remove();
                        }
                    }
                }
               
                sortChoiceContent( root );
                sortElementContent( root );
               
                if( operation.getSortSequenceContent().content() )
                {
                    sortSequenceContent( root );
                }
               
                sort( root );
               
                root.format();
               
                xmlResourceStore.save();
            }
            catch( ResourceStoreException e )
            {
                return Status.createErrorStatus( e );
            }
        }
        finally
        {
            monitor.done();
        }
       
        return Status.createOkStatus();
    }
   
    private static void create( final IContainer container ) throws CoreException
    {
        if( ! container.exists() )
        {
            create( container.getParent() );
           
            final IFolder iFolder = (IFolder) container;
            iFolder.create( true, true, null );
        }
    }
   
    private static boolean inlineIncludes( final XmlElement root,
                                           final String context,
                                           final Set<String> included )
    {
        boolean changed = false;
       
        final Element rootDomNode = root.getDomNode();
        final Document document = rootDomNode.getOwnerDocument();
       
        for( XmlElement includeElement : root.getChildElements( "include" ) )
        {
            final Element includeElementDomNode = includeElement.getDomNode();
            String includedSchemaLocation = includeElement.getAttributeText( "schemaLocation" );
           
            if( ! includedSchemaLocation.startsWith( "http://" ) )
            {
                includedSchemaLocation = context + "/" + includedSchemaLocation;
            }

            try
            {
                ByteArrayResourceStore includedSchemaResourceStore;
               
                if( includedSchemaLocation.startsWith( "http://" ) )
                {
                    includedSchemaResourceStore = new UrlResourceStore( new URL( includedSchemaLocation ) );
                }
                else
                {
                    includedSchemaResourceStore = new FileResourceStore( new File( includedSchemaLocation ) );
                }
           
                final XmlResourceStore xmlResourceStore = new XmlResourceStore( includedSchemaResourceStore );
                final XmlElement includedSchemaRoot = new XmlElement( xmlResourceStore, xmlResourceStore.getDomDocument().getDocumentElement() );
   
                for( XmlElement includedSchemaElement : includedSchemaRoot.getChildElements() )
                {
                    final Element inlinedDomNode = (Element) document.importNode( includedSchemaElement.getDomNode(), true );
                    rootDomNode.insertBefore( inlinedDomNode, includeElementDomNode );
                }
               
                includeElement.remove();
               
                changed = true;
            }
            catch( MalformedURLException e )
            {
                e.printStackTrace();
            }
            catch( ResourceStoreException e )
            {
                e.printStackTrace();
            }
        }
       
        return changed;
    }
   
    private static void removeComments( final XmlElement element )
    {
        for( XmlComment comment : element.getComments() )
        {
            comment.remove();
        }
       
        for( XmlElement x : element.getChildElements() )
        {
            removeComments( x );
        }
    }
   
    private static void removeAnnotations( final XmlElement element )
    {
        for( XmlElement x : element.getChildElements( "annotation" ) )
        {
            x.remove();
        }
       
        for( XmlElement x : element.getChildElements() )
        {
            removeAnnotations( x );
        }
    }
   
    private static void removeDefaultMinMaxOccurs( final XmlElement element )
    {
        for( XmlElement x : element.getChildElements() )
        {
            if( x.getAttributeText( "minOccurs" ).equals( "1" ) )
            {
                x.setAttributeText( "minOccurs", null, true );
            }
           
            if( x.getAttributeText( "maxOccurs" ).equals( "1" ) )
            {
                x.setAttributeText( "maxOccurs", null, true );
            }
           
            removeDefaultMinMaxOccurs( x );
        }
    }
   
    private static void removeWildcards( final XmlElement element )
    {
        for( XmlElement x : element.getChildElements( "anyAttribute" ) )
        {
            x.remove();
        }

        for( XmlElement x : element.getChildElements( "any" ) )
        {
            x.remove();
        }

        for( XmlElement x : element.getChildElements() )
        {
            removeWildcards( x );
        }
    }
   
    private static void exclude( final XmlElement element,
                                 final List<Exclusion> exclusions )
    {
        for( Exclusion exclusion : exclusions )
        {
            exclude( element, exclusion );
        }
    }

    private static void exclude( final XmlElement element,
                                 final Exclusion exclusion )
    {
        if( exclusion.getType().content() == ExclusionType.ATTRIBUTE )
        {
            excludeAttributes( element, exclusion.getName().content() );
        }
        else
        {
            excludeElements( element, exclusion.getName().content() );
        }
    }

    private static void excludeAttributes( final XmlElement element,
                                           final String name )
    {
        for( XmlElement x : element.getChildElements() )
        {
            if( x.getLocalName().equals( "attribute" ) && ( name.equals( x.getAttributeText( "name" ) ) || name.equals( x.getAttributeText( "ref" ) ) ) )
            {
                x.remove();
            }
            else
            {
                excludeAttributes( x, name );
            }
        }
    }
   
    private static void excludeElements( final XmlElement element,
                                         final String name )
    {
        for( XmlElement x : element.getChildElements() )
        {
            if( x.getLocalName().equals( "element" ) && ( name.equals( x.getAttributeText( "name" ) ) || name.equals( x.getAttributeText( "ref" ) ) ) )
            {
                x.remove();
            }
            else
            {
                excludeElements( x, name );
            }
        }
    }
   
    /**
     * Before:
     *
     * <xsd:element name="servlet-class">
     *     <xsd:complexType>
     *         <xsd:simpleContent>
     *             <xsd:restriction base="xsd:string"/>
     *         </xsd:simpleContent>
     *     </xsd:complexType>
     * </xsd:element>
     *
     * After:
     *
     * <xsd:element name="servlet-class" type="xsd:string"/>
     */
   
    private static boolean inlineRestriction( final XmlElement element )
    {
        boolean changed = false;
       
        for( XmlElement x : element.getChildElements() )
        {
            if( x.getLocalName().equals( "element" ) )
            {
                final XmlElement complexTypeElement = getSoleChildElement( x, "complexType" );
                final XmlElement simpleContentElement = getSoleChildElement( complexTypeElement, "simpleContent" );
                final XmlElement restrictionElement = getSoleChildElement( simpleContentElement, "restriction" );
               
                if( restrictionElement != null && restrictionElement.getChildElements().isEmpty() )
                {
                    final String base = restrictionElement.getAttributeText( "base" );
                   
                    if( base.length() > 0 )
                    {
                        x.setAttributeText( "type", base, false );
                        complexTypeElement.remove();
                       
                        changed = true;
                    }
                }
            }
           
            if( inlineRestriction( x ) )
            {
                changed = true;
            }
        }
       
        return changed;
    }
   
    /**
     * Before:
     *
     * <xsd:element name="servlet-class">
     *     <xsd:complexType>
     *         <xsd:simpleContent>
     *             <xsd:extension base="xsd:string"/>
     *         </xsd:simpleContent>
     *     </xsd:complexType>
     * </xsd:element>
     *
     * After:
     *
     * <xsd:element name="servlet-class" type="xsd:string"/>
     */
   
    private static boolean inlineExtension( final XmlElement element )
    {
        boolean changed = false;
       
        for( XmlElement x : element.getChildElements() )
        {
            if( x.getLocalName().equals( "element" ) )
            {
                final XmlElement complexTypeElement = getSoleChildElement( x, "complexType" );
                final XmlElement simpleContentElement = getSoleChildElement( complexTypeElement, "simpleContent" );
                final XmlElement extensionElement = getSoleChildElement( simpleContentElement, "extension" );
               
                if( extensionElement != null && extensionElement.getChildElements().isEmpty() )
                {
                    final String base = extensionElement.getAttributeText( "base" );
                   
                    if( base.length() > 0 )
                    {
                        x.setAttributeText( "type", base, false );
                        complexTypeElement.remove();
                       
                        changed = true;
                    }
                }
            }
           
            if( inlineExtension( x ) )
            {
                changed = true;
            }
        }
       
        return changed;
    }

    /**
     * Before:
     *
     * <xsd:sequence ... >
     *     <xsd:sequence>
     *         ...
     *     </xsd:sequence>
     * </xsd:sequence>
     *
     * After:
     *
     * <xsd:sequence ... >
     *     ...
     * </xsd:sequence>
     */
   
    private static boolean inlineSequenceInSequence( final XmlElement element )
    {
        boolean changed = false;
       
        if( element.getLocalName().equals( "sequence" ) )
        {
            final Element elementDomNode = element.getDomNode();
           
            for( XmlElement child : element.getChildElements() )
            {
                final Element childDomNode = child.getDomNode();
               
                if( child.getLocalName().equals( "sequence" ) && child.getAttributes().size() == 0 )
                {
                    for( XmlElement grandchild : child.getChildElements() )
                    {
                        elementDomNode.insertBefore( grandchild.getDomNode(), childDomNode );
                    }
                   
                    child.remove();
                   
                    changed = true;
                }
            }
        }
       
        for( XmlElement child : element.getChildElements() )
        {
            if( inlineSequenceInSequence( child ) )
            {
                changed = true;
            }
        }
       
        return changed;
    }

    /**
     * Before:
     *
     * <xsd:choice maxOccurs="unbounded" minOccurs="0">
     *     <xsd:sequence>
     *         <xsd:element maxOccurs="unbounded" minOccurs="0" name="a"/>
     *         <xsd:element maxOccurs="unbounded" minOccurs="0" name="b"/>
     *         <xsd:element maxOccurs="unbounded" minOccurs="0" name="c"/>
     *     </xsd:sequence>
     * </xsd:choice>
     *
     * After:
     *
     * <xsd:choice maxOccurs="unbounded" minOccurs="0">
     *     <xsd:element name="a"/>
     *     <xsd:element name="b"/>
     *     <xsd:element name="c"/>
     * </xsd:choice>
     */
   
    private static boolean inlineSequenceInChoice( final XmlElement element )
    {
        boolean changed = false;
       
        if( element.getLocalName().equals( "choice" ) && element.getAttributeText( "maxOccurs" ).equals( "unbounded" ) && element.getAttributeText( "minOccurs" ).equals( "0" ) )
        {
            final Element elementDomNode = element.getDomNode();
           
            for( XmlElement child : element.getChildElements() )
            {
                final Element childDomNode = child.getDomNode();
               
                if( child.getLocalName().equals( "sequence" ) && child.getAttributes().size() == 0 )
                {
                    boolean doit = false;
                   
                    for( XmlElement grandchild : child.getChildElements() )
                    {
                        if( grandchild.getAttributeText( "maxOccurs" ).equals( "unbounded" ) && grandchild.getAttributeText( "minOccurs" ).equals( "0" ) )
                        {
                            doit = true;
                            break;
                        }
                    }
                   
                    if( doit )
                    {
                        for( XmlElement grandchild : child.getChildElements() )
                        {
                            grandchild.setAttributeText( "maxOccurs", null, true );
                            grandchild.setAttributeText( "minOccurs", null, true );
                            elementDomNode.insertBefore( grandchild.getDomNode(), childDomNode );
                        }
                       
                        child.remove();
                       
                        changed = true;
                    }
                }
            }
        }
       
        for( XmlElement child : element.getChildElements() )
        {
            if( inlineSequenceInChoice( child ) )
            {
                changed = true;
            }
        }
       
        return changed;
    }
   
    private static boolean inlineTypes( final XmlElement element, final Map<String,XmlElement> types, final Set<String> inlined )
    {
        boolean changed = false;
       
        for( XmlElement x : element.getChildElements() )
        {
            String tname = null;
           
            if( x.getLocalName().equals( "element" ) )
            {
                tname = x.getAttributeText( "type" );
               
                if( tname.length() > 0 )
                {
                    final XmlElement type = types.get( tname );
                   
                    if( type != null )
                    {
                        x.setAttributeText( "type", null, true );
                       
                        if( ! inlined.contains( tname ) )
                        {
                            final Element xdom = x.getDomNode();
                            final Element tdom = (Element) xdom.getOwnerDocument().importNode( type.getDomNode(), true );
                           
                            tdom.removeAttribute( "name" );
                            xdom.insertBefore( tdom, null );
                           
                            changed = true;
                        }
                    }
                }
            }
           
            if( inlineTypes( x, types, SetFactory.<String>start().add( inlined ).add( tname ).result() ) )
            {
                changed = true;
            }
        }
       
        return changed;
    }
   
    private static boolean inlineElements( final XmlElement element, final Map<String,XmlElement> elements, final Set<String> inlined  )
    {
        boolean changed = false;

        final Element elementDomNode = element.getDomNode();
        final Document document = elementDomNode.getOwnerDocument();
       
        for( XmlElement x : element.getChildElements() )
        {
            String ename = null;
           
            if( x.getLocalName().equals( "element" ) )
            {
                ename = x.getAttributeText( "ref" );
               
                if( ename.length() > 0 )
                {
                    final XmlElement reftarget = elements.get( ename );
                   
                    if( reftarget != null )
                    {
                        x.setAttributeText( "ref", null, true );

                        if( ! inlined.contains( ename ) )
                        {
                            final Element xdom = x.getDomNode();
                           
                            for( XmlElement refTargetContentElement : reftarget.getChildElements() )
                            {
                                final Element idom = (Element) document.importNode( refTargetContentElement.getDomNode(), true );
                                xdom.insertBefore( idom, null );
                            }
                           
                            x.setAttributeText( "name", reftarget.getAttributeText( "name" ), false );
                            x.setAttributeText( "type", reftarget.getAttributeText( "type" ), false );
                           
                            changed = true;
                        }
                    }
                }
            }
           
            if( inlineElements( x, elements, SetFactory.<String>start().add( inlined ).add( ename ).result() ) )
            {
                changed = true;
            }
        }
       
        return changed;
    }

    private static boolean inlineGroups( final XmlElement element, final Map<String,XmlElement> groups, final Set<String> inlined )
    {
        boolean changed = false;

        final Element elementDomNode = element.getDomNode();
        final Document document = elementDomNode.getOwnerDocument();
       
        for( final XmlElement x : element.getChildElements() )
        {
            if( x.getLocalName().equals( "group" ) )
            {
                final String gname = x.getAttributeText( "ref" );
               
                if( gname.length() > 0 )
                {
                    final XmlElement group = groups.get( gname );
                   
                    if( group != null )
                    {
                        final boolean repeat = inlined.contains( gname );
                        final Element xdom = x.getDomNode();
                       
                        for( final XmlElement groupContentElement : group.getChildElements() )
                        {
                            final Element gdom = (Element) document.importNode( groupContentElement.getDomNode(), ! repeat );
                            elementDomNode.insertBefore( gdom, xdom );
                           
                            if( ! repeat )
                            {
                                inlineGroups( element.getChildElement( gdom ), groups, SetFactory.<String>start().add( inlined ).add( gname ).result() );
                            }
                        }
                       
                        elementDomNode.removeChild( xdom );
                       
                        changed = true;
                    }
                }
            }
            else if( inlineGroups( x, groups, inlined ) )
            {
                changed = true;
            }
        }
       
        return changed;
    }
   
    /**
     * Before:
     *
     * <xsd:choice maxOccurs="unbounded" minOccurs="0">
     *     <xsd:element maxOccurs="unbounded" minOccurs="0" name="a"/>
     *     <xsd:element minOccurs="0" name="b"/>
     * </xsd:choice>
     *
     * After:
     *
     * <xsd:choice maxOccurs="unbounded" minOccurs="0">
     *     <xsd:element name="a"/>
     *     <xsd:element name="b"/>
     * </xsd:choice>
     */
   
    private static boolean removeRedundantMinMaxOccursInChoice( final XmlElement element )
    {
        boolean changed = false;
       
        if( element.getLocalName().equals( "choice" ) && element.getAttributeText( "maxOccurs" ).equals( "unbounded" ) && element.getAttributeText( "minOccurs" ).equals( "0" ) )
        {
            for( XmlElement child : element.getChildElements() )
            {
                if( child.getAttributeText( "maxOccurs" ).equals( "unbounded" ) )
                {
                    child.setAttributeText( "maxOccurs", null, true );
                    changed = true;
                }
               
                if( child.getAttributeText( "minOccurs" ).equals( "0" ) )
                {
                    child.setAttributeText( "minOccurs", null, true );
                    changed = true;
                }
            }
        }
       
        for( XmlElement child : element.getChildElements() )
        {
            if( removeRedundantMinMaxOccursInChoice( child ) )
            {
                changed = true;
            }
        }
       
        return changed;
    }
   
    private static boolean applyTypeSubstitutions( final XmlElement element,
                                                   final Map<String,String> typeSubstitutions )
    {
        boolean changed = false;
       
        if( applyTypeSubstitutions( element, "type", typeSubstitutions ) )
        {
            changed = true;
        }
       
        if( applyTypeSubstitutions( element, "base", typeSubstitutions ) )
        {
            changed = true;
        }
       
        for( XmlElement child : element.getChildElements() )
        {
            if( applyTypeSubstitutions( child, typeSubstitutions ) )
            {
                changed = true;
            }
        }
       
        return changed;
    }
   
    private static boolean applyTypeSubstitutions( final XmlElement element,
                                                   final String attribute,
                                                   final Map<String,String> typeSubstitutions )
    {
        boolean changed = false;
       
        final String before = element.getAttributeText( attribute );
       
        if( before.length() > 0 )
        {
            final String after = typeSubstitutions.get( before );
           
            if( after != null )
            {
                element.setAttributeText( attribute, after, false );
                changed = true;
            }
        }
       
        return changed;
    }
   
    private static void sortChoiceContent( final XmlElement element )
    {
        if( element.getLocalName().equals( "choice" ) )
        {
            sort( element, new SchemaContentComparator() );
        }
       
        for( XmlElement child : element.getChildElements() )
        {
            sortChoiceContent( child );
        }
    }

    private static void sortSequenceContent( final XmlElement element )
    {
        if( element.getLocalName().equals( "sequence" ) )
        {
            sort( element, new SchemaContentComparator() );
        }
       
        for( XmlElement child : element.getChildElements() )
        {
            sortSequenceContent( child );
        }
    }
   
    private static void sortElementContent( final XmlElement element )
    {
        if( element.getLocalName().equals( "element" ) )
        {
            sort( element, new ElementChildrenComparator() );
        }
       
        for( XmlElement child : element.getChildElements() )
        {
            sortElementContent( child );
        }
    }
   
    private static void sort( final XmlElement element,
                              final Comparator<XmlElement> comparator )
    {
        final List<XmlElement> children = new ArrayList<XmlElement>();
       
        for( XmlElement child : element.getChildElements() )
        {
            children.add( child );
            child.remove();
        }
       
        Collections.sort( children, comparator );
       
        final Element rootDomElement = element.getDomNode();
       
        for( XmlElement child : children )
        {
            rootDomElement.insertBefore( child.getDomNode(), null );
        }
    }
   
    private static void sort( final XmlElement root )
    {
        final List<XmlElement> elements = new ArrayList<XmlElement>();
       
        for( XmlElement x : root.getChildElements() )
        {
            elements.add( x );
            x.remove();
        }
       
        Collections.sort( elements, new SchemaContentComparator() );
       
        final Element rootDomElement = root.getDomNode();
       
        for( XmlElement x : elements )
        {
            rootDomElement.insertBefore( x.getDomNode(), null );
        }
    }
   
    private static void changeSchemaNamespacePrefix( final Document document,
                                                     final String prefix )
    {
        final Element root = document.getDocumentElement();
       
        if( root != null )
        {
            final String newPrefix = ( prefix.equals( "" ) ? null : prefix );
            final NamedNodeMap attributes = root.getAttributes();
            boolean doit = false;
            String oldPrefix = null;
           
            for( int i = 0, count = attributes.getLength(); i < count; i++ )
            {
                final Attr attribute = (Attr) attributes.item( i );
                final String name = attribute.getName();
                final String value = attribute.getValue();
               
                if( name.equals( "xmlns" ) && value.equals( NS_SCHEMA ) )
                {
                    if( newPrefix != null )
                    {
                        root.removeAttributeNode( attribute );
                        doit = true;
                    }
                   
                    break;
                }
                else if( name.startsWith( "xmlns:" ) && value.equals( NS_SCHEMA ) )
                {
                    oldPrefix = name.substring( 6 );
                   
                    if( ! oldPrefix.equals( newPrefix ) )
                    {
                        root.removeAttributeNode( attribute );
                        doit = true;
                    }
                   
                    break;
                }
            }
           
            if( doit )
            {
                if( newPrefix == null )
                {
                    root.setAttribute( "xmlns", NS_SCHEMA );
                }
                else
                {
                    root.setAttribute( "xmlns:" + newPrefix, NS_SCHEMA );
                }
            }
           
            changeSchemaNamespacePrefix( root, oldPrefix, newPrefix );
        }
    }
   
    private static void changeSchemaNamespacePrefix( final Node node,
                                                     final String oldPrefix,
                                                     final String newPrefix )
    {
        if( node instanceof Element )
        {
            final Element element = (Element) node;
           
            if( NS_SCHEMA.equals( element.getNamespaceURI() ) )
            {
                final NodeList children = element.getChildNodes();
               
                for( int i = 0, n = children.getLength(); i < n; i++ )
                {
                    changeSchemaNamespacePrefix( children.item( i ), oldPrefix, newPrefix );
                }
               
                element.getOwnerDocument().renameNode( element, NS_SCHEMA, ( newPrefix == null ? "" : newPrefix + ":" ) + element.getLocalName() );
               
                changeSchemaNamespacePrefix( element, "type", oldPrefix, newPrefix );
                changeSchemaNamespacePrefix( element, "base", oldPrefix, newPrefix );
            }
        }
    }
   
    private static void changeSchemaNamespacePrefix( final Element element,
                                                     final String attribute,
                                                     final String oldPrefix,
                                                     final String newPrefix )
    {
        final String type = element.getAttribute( attribute );
       
        if( type.length() > 0 )
        {
            final int colon = type.indexOf( ':' );
            final String typePrefix = ( colon == -1 ? null : type.substring( 0, colon ) );
           
            if( equal( typePrefix, oldPrefix ) )
            {
                final String typeWithoutPrefix = ( colon == -1 ? type : type.substring( colon + 1 ) );
                element.setAttribute( attribute, ( newPrefix == null ? "" : newPrefix + ":" ) + typeWithoutPrefix );
            }
        }
    }
   
    private static XmlElement getSoleChildElement( final XmlElement element,
                                                   final String name )
    {
        if( element != null )
        {
            final List<XmlElement> children = element.getChildElements();
           
            if( children.size() == 1 )
            {
                final XmlElement child = children.get( 0 );
               
                if( child.getLocalName().equals( name ) )
                {
                    return child;
                }
            }
        }
       
        return null;
    }

    private static final class SchemaContentComparator implements Comparator<XmlElement>
    {
        public int compare( final XmlElement x, final XmlElement y )
        {
            int result = x.getLocalName().compareTo( y.getLocalName() );
           
            if( result == 0 )
            {
                result = x.getAttributeText( "name" ).compareTo( y.getAttributeText( "name" ) );
            }
           
            return result;
        }
    }
   
    private static final class ElementChildrenComparator implements Comparator<XmlElement>
    {
        public int compare( final XmlElement x, final XmlElement y )
        {
            int result = bucket( x ) - bucket( y );
           
            if( result == 0 )
            {
                result = x.getLocalName().compareTo( y.getLocalName() );
               
                if( result == 0 )
                {
                    result = x.getAttributeText( "name" ).compareTo( y.getAttributeText( "name" ) );
                }
            }
           
            return result;
        }
       
        private int bucket( final XmlElement element )
        {
            final String name = element.getLocalName();
           
            if( name.equals( "simpleType" ) || name.equals( "complexType" ) )
            {
                return 1;
            }
            else if( name.equals( "unique" ) || name.equals( "key" ) || name.equals( "keyref" ) )
            {
                return 2;
            }
            else
            {
                return 3;
            }
        }
    }
   
}
TOP

Related Classes of org.eclipse.sapphire.sdk.xml.schema.normalizer.internal.CreateNormalizedXmlSchemaOpMethods$ElementChildrenComparator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.