XmlUtils.java :  » Web-Services » soapui-1.7.5 » com » eviware » soapui » support » xml » Java Open Source

Java Open Source » Web Services » soapui 1.7.5 
soapui 1.7.5 » com » eviware » soapui » support » xml » XmlUtils.java
/*
 *  soapUI, copyright (C) 2004-2007 eviware.com 
 *
 *  soapUI is free software; you can redistribute it and/or modify it under the 
 *  terms of version 2.1 of the GNU Lesser General Public License as published by 
 *  the Free Software Foundation.
 *
 *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
 *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 *  See the GNU Lesser General Public License for more details at gnu.org.
 */

package com.eviware.soapui.support.xml;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.log4j.Logger;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.wsdl.WsdlInterface;
import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
import com.eviware.soapui.support.types.StringToStringMap;

/**
 * General XML-related utilities
 */

public final class XmlUtils
{
   private static DocumentBuilder documentBuilder;
   private final static Logger log = Logger.getLogger( XmlUtils.class );

   static public Document parse( InputStream in )
   {
      try
      {
         return ensureDocumentBuilder().parse( in );
      }
      catch( Exception e )
      {
        log.error( "Error parsing InputStream; " + e.getMessage(), e );
      }

      return null;
   }

   static public Document parse( String fileName ) throws IOException
   {
      try
      {
         return  ensureDocumentBuilder().parse( fileName );
      }
      catch( SAXException e )
      {
        log.error( "Error parsing fileName [" + fileName + "]; " + e.getMessage(), e );
      }

      return null;
   }
   
   public static String entitize( String xml )
   {
     return xml.replaceAll( "&", "&amp;" ).replaceAll( "<", "&lt;" ).replaceAll( ">", "&gt;" ).
       replaceAll( "\"", "&quot;" ).replaceAll( "'", "&apos;" );
   }

   static public Document parse( InputSource inputSource ) throws IOException
   {
      try
      {
         return ensureDocumentBuilder().parse( inputSource );
      }
      catch( SAXException e )
      {
        throw new IOException( e.toString() );
      }
   }

   private static DocumentBuilder ensureDocumentBuilder()
   {
      if( documentBuilder == null )
      {
         try
         {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            dbf.setNamespaceAware( true );
        documentBuilder = dbf.newDocumentBuilder();
         }
         catch( ParserConfigurationException e )
         {
           log.error( "Error creating DocumentBuilder; " + e.getMessage() );
         }
      }

      return documentBuilder;
   }

   public static void serializePretty( Document document )
   {
      try
      {
         serializePretty( document, new OutputStreamWriter( System.out ) );
      }
      catch( IOException e )
      {
         log.error( "Failed to seraialize: " + e );
      }
   }

   public static void serializePretty( Document dom, Writer writer )
      throws IOException
   {
     try
    {
      XmlObject xmlObject = XmlObject.Factory.parse(dom.getDocumentElement());
      serializePretty(xmlObject, writer);
    }
    catch (Exception e)
    {
      throw new IOException( e.toString() );
    }
   }
   
   public static void serializePretty( XmlObject xmlObject, Writer writer ) throws IOException
  {
    XmlOptions options = new XmlOptions();
    options.setSavePrettyPrint();
    options.setSavePrettyPrintIndent( 3 );
    options.setSaveNoXmlDecl();
    options.setSaveAggressiveNamespaces();
    xmlObject.save(writer, options);
  }

   public static void serialize( Document dom, Writer writer )
   throws IOException
  {
     serialize( dom.getDocumentElement(), writer );
  }
   
   public static void serialize( Element elm, Writer writer )
   throws IOException
  {
     try
    {
      XmlObject xmlObject = XmlObject.Factory.parse(elm);
      xmlObject.save( writer );
    }
    catch (XmlException e)
    {
      throw new IOException( e.toString() );
    }
  }
   
   static public void setElementText( Element elm, String text )
   {
      Node node = elm.getFirstChild();
      if( node == null  )
      {
        if( text != null)
          elm.appendChild( elm.getOwnerDocument().createTextNode( text ) );
      }
      else if( node.getNodeType() == Node.TEXT_NODE )
      {
         if( text == null )
            node.getParentNode().removeChild( node );
         else
            node.setNodeValue( text );
      }
      else if( text != null )
      {
         Text textNode = node.getOwnerDocument().createTextNode( text );
         elm.insertBefore( textNode, elm.getFirstChild() );
      }
   }

   public static String getChildElementText( Element elm, String name )
   {
      Element child = getFirstChildElement( elm, name );
      return child == null ? null : getElementText( child );
   }

   public static Element getFirstChildElement( Element elm )
   {
     return getFirstChildElement( elm, null );
   }
   
   public static Element getFirstChildElement( Element elm, String name )
   {
      NodeList nl = elm.getChildNodes();
      for( int c = 0; c < nl.getLength(); c++ )
      {
         Node node = nl.item( c );
         if( node.getNodeType() == Node.ELEMENT_NODE && (name == null || node.getNodeName().equals( name )) )
            return (Element) node;
      }

      return null;
   }
   
   public static Element getFirstChildElementNS( Element elm, String tns, String localName )
   {
     if( tns == null && localName == null )
       return getFirstChildElement( elm );
     
     if( tns == null )
       return getFirstChildElement( elm, localName );
     
      NodeList nl = elm.getChildNodes();
      for( int c = 0; c < nl.getLength(); c++ )
      {
         Node node = nl.item( c );
         if( node.getNodeType() != Node.ELEMENT_NODE ) continue;
         
         if( localName == null && tns.equals( node.getNamespaceURI() ))
           return ( Element ) node;
         
         if( localName != null && tns.equals( node.getNamespaceURI() ) && localName.equals( node.getLocalName() ))
           return ( Element ) node;
      }

      return null;
   }

   static public String getElementText( Element elm )
   {
      Node node = elm.getFirstChild();
      if( node != null && node.getNodeType() == Node.TEXT_NODE )
         return node.getNodeValue();

      return null;
   }
   
   static public String getFragmentText( DocumentFragment elm )
   {
      Node node = elm.getFirstChild();
      if( node != null && node.getNodeType() == Node.TEXT_NODE )
         return node.getNodeValue();

      return null;
   }

   public static String getChildElementText( Element elm, String name, String defaultValue )
   {
      String result = getChildElementText( elm, name );
      return result == null ? defaultValue : result;
   }

   static public String getNodeValue( Node node )
   {
     if( node.getNodeType() == Node.ELEMENT_NODE )
       return getElementText( (Element) node );
     else if( node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE )
       return getFragmentText( (DocumentFragment) node );
     else 
       return node.getNodeValue();
   }

   public static Node createNodeFromPath( Element modelElement, String path )
   {
      Document document = modelElement.getOwnerDocument();
      StringTokenizer st = new StringTokenizer( path, "/" );
      while( st.hasMoreTokens() )
      {
         String t = st.nextToken();

         if( st.hasMoreTokens() )
         {
            if( t.equals( ".." ) )
            {
               modelElement = (Element) modelElement.getParentNode();
            }
            else
            {
               Element elm = getFirstChildElement( modelElement, t );
               if( elm == null )
                  modelElement = (Element) modelElement.insertBefore(
                     document.createElement( t ),
                     getFirstChildElement( modelElement, t ) );
               else
                  modelElement = elm;
            }
         }
         else
         {
            modelElement = (Element) modelElement.insertBefore(
               document.createElement( t ),
               getFirstChildElement( modelElement, t ) );
         }
      }

      return modelElement;
   }

   public static Element addChildElement( Element element, String name, String text )
   {
      Document document = element.getOwnerDocument();
      Element result = (Element) element.appendChild( document.createElement( name ) );
      if( text != null )
         result.appendChild( document.createTextNode( text ) );

      return result;
   }

   public static void setChildElementText( Element element, String name, String text )
   {
      Element elm = getFirstChildElement( element, name );
      if( elm == null )
      {
         elm = element.getOwnerDocument().createElement( name );
         element.appendChild( elm );
      }

      setElementText( elm, text );
   }

   public static Document parseXml( String xmlString ) throws IOException
   {
      return parse( new InputSource( new StringReader( xmlString )));
   }
   
   public static void dumpParserErrors(XmlObject xmlObject)
   {
      List errors = new ArrayList();
      xmlObject.validate(new XmlOptions().setErrorListener(errors));
      for (Iterator i = errors.iterator(); i.hasNext();)
      {
         System.out.println(i.next());
      }
   }

  public static String transferValues(String source, String dest)
  {
    XmlCursor cursor = null;
    try
    {
      XmlObject sourceXml = XmlObject.Factory.parse( source );
      XmlObject destXml = XmlObject.Factory.parse( dest );
      
      cursor = sourceXml.newCursor();
      cursor.toNextToken();
      while( !cursor.isEnddoc() )
      {
        while( !cursor.isContainer() && !cursor.isEnddoc() )
          cursor.toNextToken();
        
        if( cursor.isContainer() )
        {
          Element elm = ( Element ) cursor.getDomNode();
          String path = createXPath( elm );
          XmlObject[] paths = destXml.selectPath( path );
          if( paths != null && paths.length > 0 )
          {
            Element elm2 = ( Element ) paths[0].getDomNode();
            
            // transfer attributes
            NamedNodeMap attributes = elm.getAttributes();
            for( int c = 0; c < attributes.getLength(); c++ )
            {
              Attr attr = (Attr) attributes.item( c );
              elm2.setAttribute( attr.getNodeName(), attr.getNodeValue() );
            }
            
            // transfer text
            setElementText( elm2, getElementText( elm ));
          }
          
          cursor.toNextToken();
        }
      }

      return destXml.xmlText();
    }
    catch (Exception e)
    {
      SoapUI.logError( e );
    }
    finally
    {
      if( cursor != null )
        cursor.dispose();
    }
    
    return dest;
  }

  /**
   * Returns absolute xpath for specified element, ignores namespaces
   *  
   * @param elm the element to create for
   * @return the elements path in its containing document
   */
  
  public static String getElementPath(Element element)
  {
    Node elm = element;
    
    String result = elm.getNodeName() + "[" + getElementIndex( elm ) + "]";
    while( elm.getParentNode() != null && elm.getParentNode().getNodeType() != Node.DOCUMENT_NODE )
    {
      elm = elm.getParentNode();
      result = elm.getNodeName() + "[" + getElementIndex( elm ) + "]/" + result;
    }

    return "/" + result;
  }

  /**
   * Gets the index of the specified element amongst elements with the same name
   * 
   * @param element the element to get for
   * @return the index of the element, will be >= 1
   */
  
  public static int getElementIndex(Node element)
  {
    int result = 1;
    
    Node elm = element.getPreviousSibling();
    while( elm != null )
    {
      if( elm.getNodeType() == Node.ELEMENT_NODE && elm.getNodeName().equals( element.getNodeName() ))
        result++;
      elm = elm.getPreviousSibling();
    }
    
    return result;  
  }
  
  public static String declareXPathNamespaces( String xmlString ) throws XmlException
  {
    return declareXPathNamespaces( XmlObject.Factory.parse(xmlString));
  }
  
  public static synchronized String prettyPrintXml( String xml )
  {
      try
      {
        if( xml == null )
          return null;
        
         StringWriter writer = new StringWriter();
         XmlUtils.serializePretty( XmlObject.Factory.parse( xml ), writer );
         return writer.toString();
      }
      catch( Exception e )
      {
        log.warn( "Failed to prettyPrint xml: " + e );
         return xml;
      }
  }
  
  public static synchronized String prettyPrintXml( XmlObject xml )
  {
      try
      {
        if( xml == null )
          return null;
        
         StringWriter writer = new StringWriter();
         XmlUtils.serializePretty( xml, writer );
         return writer.toString();
      }
      catch( Exception e )
      {
        log.warn( "Failed to prettyPrint xml: " + e );
         return xml.xmlText();
      }
  }

  public static String declareXPathNamespaces(WsdlInterface iface)
  {
    StringBuffer buf = new StringBuffer();
    buf.append( "declare namespace soap='" );
    buf.append( iface.getSoapVersion().getEnvelopeNamespace() );
    buf.append( "';\n");
    
    try
    {
      Collection<String> namespaces = iface.getWsdlContext().getDefinedNamespaces();
      int c = 1;
      for (Iterator<String> i = namespaces.iterator(); i.hasNext();)
      {
        buf.append("declare namespace ns");
        buf.append(c++);
        buf.append("='");
        buf.append(i.next());
        buf.append("';\n");
      }
    }
    catch (Exception e)
    {
      SoapUI.logError( e );
    }    
    
    return buf.toString();
  }
  
  public static String createXPath(Node node )
  {
    return createXPath( node, false, false, null );
  }
  
  public static String createXPath(Node node, boolean anonymous, boolean selectText, XPathModifier modifier )
  {
    StringToStringMap nsMap = new StringToStringMap();
    int nsCnt = 1;
    List<String> pathComponents = new ArrayList<String>();
    
    String namespaceURI = node.getNamespaceURI();
    if( node.getNodeType() == Node.ATTRIBUTE_NODE )
    {
      if( namespaceURI.length() > 0 )
      {
        String prefix = node.getPrefix();
        if( prefix == null || prefix.length() == 0 )
          prefix = "ns" + nsCnt++;
        
        nsMap.put( namespaceURI, prefix );
        pathComponents.add( "@" + prefix + ":" + node.getLocalName() );
      }
      else
      {
        pathComponents.add( "@" + node.getLocalName() );
      }
      node = ((Attr)node).getOwnerElement();
    }
    
    if( node.getNodeType() == Node.ELEMENT_NODE )
    {
      int index = anonymous ? 0 : findNodeIndex( node );
      
      String pc = null;
    
      namespaceURI = node.getNamespaceURI();
      if( namespaceURI.length() > 0 )
      {
        String prefix = node.getPrefix();
        if( prefix == null || prefix.length() == 0 )
          prefix = "ns" + nsCnt++;
        
        nsMap.put( namespaceURI, prefix );
        pc = prefix + ":" + node.getLocalName();
      }
      else
      {
        pc = node.getLocalName();
      }
      
      String elementText = XmlUtils.getElementText( (Element) node );
      
      // not an attribute?
      if( selectText && pathComponents.isEmpty() && elementText != null && elementText.trim().length() > 0  )
        pathComponents.add( "text()" );
      
      pathComponents.add( pc + ((index == 0 ) ? "" : "[" + index + "]" ));
    }
    else
      return null;
    
    node = node.getParentNode();
    namespaceURI = node.getNamespaceURI();
    while( node != null && node.getNodeType() == Node.ELEMENT_NODE && 
        !node.getNodeName().equals( "Body" ) && 
        !namespaceURI.equals( SoapVersion.Soap11.getEnvelopeNamespace() ) &&
        !namespaceURI.equals( SoapVersion.Soap12.getEnvelopeNamespace() ))
    {
      int index = anonymous ? 0 : findNodeIndex( node );
      
      String ns = nsMap.get( namespaceURI );
      String pc = null;
      
      if( ns == null && namespaceURI.length() > 0 )
      {
        String prefix = node.getPrefix();
        if( prefix == null || prefix.length() == 0 )
          prefix = "ns" + nsCnt++;
        
        nsMap.put( namespaceURI, prefix );
        ns = nsMap.get( namespaceURI );
        
        pc = prefix + ":" + node.getLocalName();
      }
      else if( ns != null ) 
      {
         pc = ns + ":" + node.getLocalName();
      }
      else
      {
         pc = node.getLocalName();
      }
      
      pathComponents.add( pc + ((index == 0 ) ? "" : "[" + index + "]" ));
      node = node.getParentNode();
      namespaceURI = node.getNamespaceURI();
    }
    
    StringBuffer xpath = new StringBuffer();

    for( Iterator<String> i = nsMap.keySet().iterator(); i.hasNext(); )
    {
      String ns = i.next();
      xpath.append( "declare namespace " + nsMap.get( ns ) + "='" + ns + "';\n");
    }
    
    if( modifier != null )
      modifier.beforeSelector( xpath );
    
    xpath.append( "/" );
    
    for( int c = pathComponents.size()-1; c >= 0; c-- )
    {
      xpath.append( "/" ).append( pathComponents.get( c ));
    }
    
    if( modifier != null )
      modifier.afterSelector( xpath );
    
    return xpath.toString();
  }

  private static int findNodeIndex(Node node)
  {
    String nm = node.getLocalName();
    String ns = node.getNamespaceURI();
    
    Node parentNode = node.getParentNode();
    if( parentNode.getNodeType() != Node.ELEMENT_NODE )
      return 1;
    
    NodeList nl = ((Element)parentNode).getElementsByTagNameNS( ns, nm );
    
    if( nl.getLength() == 1 )
      return 0;
    
    int mod = 0;
    for( int c = 0; c < nl.getLength(); c++ )
    {
      if( nl.item( c ).getParentNode() != node.getParentNode() )
        mod++;
      else if( nl.item( c ) == node )
        return c+1-mod;
    }
    
    throw new RuntimeException( "Child node not found in parent!?" );
  }

  public static boolean setNodeValue( Node domNode, String string )
  {
    short nodeType = domNode.getNodeType();
    if( nodeType == Node.ELEMENT_NODE )
    {
      setElementText( ( Element ) domNode, string );
      return true;
    }
    else if( nodeType == Node.ATTRIBUTE_NODE || nodeType == Node.TEXT_NODE )
    {
      domNode.setNodeValue( string );
      return true;
    }
    
    return false;
  }

  public static String declareXPathNamespaces( XmlObject xmlObject )
  {
    Map<QName,String> map = new HashMap<QName,String>();
    XmlCursor cursor = xmlObject.newCursor();
    
    while( cursor.hasNextToken() )
    {
      if( cursor.toNextToken().isNamespace() )
        map.put( cursor.getName(), cursor.getTextValue() );
    }
    
    Iterator<QName> i = map.keySet().iterator();
    int nsCnt = 0;
    
    StringBuffer buf = new StringBuffer();
    Set<String> prefixes = new HashSet<String>();
    Set<String> usedPrefixes = new HashSet<String>();
    
    while( i.hasNext() )
    {
      QName name = i.next();
      String prefix = name.getLocalPart();
      if( prefix.length() == 0 ) prefix = "ns" + Integer.toString( ++nsCnt );
      else if( prefix.equals( "xsd") || prefix.equals( "xsi")) continue;
      
      if( usedPrefixes.contains( prefix ))
      {
        int c = 1;
        while( usedPrefixes.contains( prefix + c )) c++;
        
        prefix = prefix + Integer.toString( c );
      }
      else prefixes.add( prefix );
      
      buf.append( "declare namespace " );
      buf.append( prefix );
      buf.append( "='" );
      buf.append( map.get( name ));
      buf.append( "';\n");
      
      usedPrefixes.add( prefix );
    }
    
    return buf.toString();
  }

  public static String setXPathContent( String emptyResponse, String string, String actor )
  {
    try
    {
      XmlObject xmlObject = XmlObject.Factory.parse( emptyResponse );
      
      String namespaces = declareXPathNamespaces( xmlObject );
      if( namespaces != null && namespaces.trim().length() > 0 )
        string = namespaces + string;
      
      XmlObject[] path = xmlObject.selectPath( string );
      for( XmlObject xml : path )
      {
        setNodeValue( xml.getDomNode(), actor );
      }
      
      return xmlObject.toString();
    }
    catch( Exception e )
    {
      SoapUI.logError( e );
    }
    
    return emptyResponse;
  }
  
  public static QName getQName( Node node )
  {
    if( node.getNamespaceURI() == null )
      return new QName( node.getNodeName());
    else
      return new QName( node.getNamespaceURI(), node.getLocalName() );
  }

  public static String removeXPathNamespaceDeclarations( String xpath )
  {
    while( xpath.startsWith( "declare namespace" ))
    {
      int ix = xpath.indexOf( ';' );
      if( ix == -1 )
        break;
      
      xpath = xpath.substring( ix+1 ).trim();
    }
    return xpath;
  }

  public static String stripWhitespaces( String content )
  {
    try
    {
      XmlObject xml = XmlObject.Factory.parse( content, new XmlOptions().setLoadStripWhitespace().setLoadStripComments() );
      content = xml.xmlText();
    }
    catch( Exception e )
    {
      SoapUI.logError( e );
    }
    
    return content;
  }

  public static NodeList getChildElements( Element elm )
  {
    List<Element> list = new ArrayList<Element>();
    
    NodeList nl = elm.getChildNodes();
    for( int c = 0; c < nl.getLength(); c++ )
    {
      if( nl.item( c ).getNodeType() == Node.ELEMENT_NODE )
        list.add(  ( Element ) nl.item( c ) );
    }
    
    return new ElementNodeList( list );
  }

  private final static class ElementNodeList implements NodeList
  {
    private final List<Element> list;

    public ElementNodeList( List<Element> list )
    {
      this.list = list;
    }

    public int getLength()
    {
      return list.size();
    }

    public Node item( int index )
    {
      return list.get( index );
    }}

  public static boolean seemsToBeXml( String str )
  {
    try
    {
      return str != null && XmlObject.Factory.parse( str ) != null;
    }
    catch( Exception e )
    {
      return false;
    }
  }

  public static String extractNamespaces( String xpath )
  {
    String result = xpath;
    int ix = xpath.lastIndexOf( "declare namespace" );
    if( ix != -1 )
    {
      ix = xpath.indexOf( '\'', ix+1 );
      if( ix != -1 )
      {
        ix = xpath.indexOf( '\'', ix+1 );
        if( ix != -1 )
        {
          ix = xpath.indexOf( ';' );
          if( ix != -1 )
          {
            result = xpath.substring( 0, ix+1 );
          }
        }
      }
    }
    
    return result;
  }
}

java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.