Coverage Report - org.apache.maven.shared.utils.xml.Xpp3DomBuilder
 
Classes in this File Line Coverage Branch Coverage Complexity
Xpp3DomBuilder
55%
11/20
N/A
1.938
Xpp3DomBuilder$DocHandler
84%
39/46
91%
11/12
1.938
 
 1  
 package org.apache.maven.shared.utils.xml;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *  http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import org.apache.maven.shared.utils.io.IOUtil;
 23  
 import org.apache.maven.shared.utils.xml.pull.XmlPullParserException;
 24  
 
 25  
 import org.xml.sax.*;
 26  
 import org.xml.sax.helpers.DefaultHandler;
 27  
 
 28  
 import javax.annotation.Nonnull;
 29  
 import javax.annotation.WillClose;
 30  
 import java.io.*;
 31  
 import java.util.ArrayList;
 32  
 import java.util.List;
 33  
 
 34  
 /**
 35  
  * @author Kristian Rosenvold
 36  
  */
 37  0
 public class Xpp3DomBuilder
 38  
 {
 39  
     private static final boolean DEFAULT_TRIM = true;
 40  
 
 41  
     public static Xpp3Dom build( @WillClose @Nonnull Reader reader )
 42  
         throws XmlPullParserException
 43  
     {
 44  22
         return build( reader, DEFAULT_TRIM );
 45  
     }
 46  
 
 47  
     public static Xpp3Dom build( @WillClose InputStream is, @Nonnull String encoding )
 48  
         throws XmlPullParserException
 49  
     {
 50  0
         return build( is, encoding, DEFAULT_TRIM );
 51  
     }
 52  
 
 53  
     public static Xpp3Dom build( @WillClose InputStream is, @Nonnull String encoding, boolean trim )
 54  
         throws XmlPullParserException
 55  
     {
 56  
         try {
 57  0
             Reader reader = new InputStreamReader(is, encoding);
 58  0
             return build( reader, trim);
 59  0
         } catch (UnsupportedEncodingException e) {
 60  0
             throw new RuntimeException(e);
 61  
         }
 62  
     }
 63  
 
 64  
     public static Xpp3Dom build( @WillClose Reader reader, boolean trim )
 65  
             throws XmlPullParserException
 66  
     {
 67  
         try
 68  
         {
 69  24
             DocHandler docHandler = parseSax(new InputSource(reader), trim);
 70  23
             return docHandler.result;
 71  
         }
 72  
         finally
 73  
         {
 74  23
             IOUtil.close( reader );
 75  
         }
 76  
     }
 77  
 
 78  
     private static DocHandler parseSax(@Nonnull InputSource inputSource, boolean trim) throws XmlPullParserException {
 79  
 
 80  
         try {
 81  24
             DocHandler ch = new DocHandler(trim);
 82  24
             XMLReader parser = org.xml.sax.helpers.XMLReaderFactory.createXMLReader();
 83  24
             parser.setContentHandler( ch);
 84  24
             parser.parse(inputSource);
 85  23
             return ch;
 86  0
         } catch (IOException e){
 87  0
             throw new XmlPullParserException(e);
 88  1
         } catch (SAXException e) {
 89  1
             throw new XmlPullParserException(e);
 90  
         }
 91  
     }
 92  
 
 93  
 
 94  0
     private static class DocHandler extends DefaultHandler {
 95  24
         private final List<Xpp3Dom> elemStack = new ArrayList<Xpp3Dom>();
 96  24
         private final List<StringBuilder> values = new ArrayList<StringBuilder>();
 97  
 
 98  
         // Todo: Use these for something smart !
 99  24
         private final List<SAXParseException> warnings = new ArrayList<SAXParseException>();
 100  24
         private final List<SAXParseException> errors = new ArrayList<SAXParseException>();
 101  24
         private final List<SAXParseException> fatals = new ArrayList<SAXParseException>();
 102  
 
 103  
 
 104  24
         Xpp3Dom result = null;
 105  
 
 106  
         private final boolean trim;
 107  
 
 108  24
         DocHandler(boolean trim) {
 109  24
             this.trim = trim;
 110  24
         }
 111  
 
 112  
         @Override
 113  
         public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
 114  
 
 115  77
             Xpp3Dom child = new Xpp3Dom( localName );
 116  
 
 117  77
             attachToParent(child);
 118  77
             pushOnStack(child);
 119  
 
 120  
             // Todo: Detecting tags that close immediately seem to be impossible in sax ?
 121  
             // http://stackoverflow.com/questions/12968390/detecting-self-closing-tags-in-sax
 122  77
             values.add( new StringBuilder() );
 123  
 
 124  77
             int size = attributes.getLength();
 125  91
             for ( int i = 0; i < size; i++ )
 126  
             {
 127  14
                 child.setAttribute(attributes.getQName(i), attributes.getValue(i));
 128  
             }
 129  77
         }
 130  
 
 131  
         private boolean pushOnStack(Xpp3Dom child) {
 132  77
             return elemStack.add(child);
 133  
         }
 134  
 
 135  
         private void attachToParent(Xpp3Dom child) {
 136  77
             int depth = elemStack.size();
 137  77
             if ( depth > 0 )
 138  
             {
 139  53
                 elemStack.get(depth - 1).addChild(child);
 140  
             }
 141  77
         }
 142  
 
 143  
         @Override
 144  
         public void warning(SAXParseException e) throws SAXException {
 145  0
             warnings.add(e);
 146  0
         }
 147  
 
 148  
         @Override
 149  
         public void error(SAXParseException e) throws SAXException {
 150  0
             errors.add(e);
 151  0
         }
 152  
 
 153  
         @Override
 154  
         public void fatalError(SAXParseException e) throws SAXException {
 155  0
             fatals.add(e);
 156  0
         }
 157  
 
 158  
 
 159  
         private Xpp3Dom pop()
 160  
         {
 161  76
             int depth = elemStack.size() - 1;
 162  76
             return elemStack.remove( depth );
 163  
         }
 164  
 
 165  
         @Override
 166  
         public void endElement(String uri, String localName, String qName) throws SAXException {
 167  76
             int depth = elemStack.size() - 1;
 168  
 
 169  76
             Xpp3Dom finishedConfiguration = pop();
 170  
 
 171  
                 /* this Object could be null if it is a singleton tag */
 172  76
             Object accumulatedValue = values.remove( depth );
 173  
 
 174  76
             if ( finishedConfiguration.getChildCount() == 0 )
 175  
             {
 176  44
                 if ( accumulatedValue == null )
 177  
                 {
 178  0
                     finishedConfiguration.setValue( "" ); // null in xpp3dom, but we dont do that around here
 179  
                 }
 180  
                 else
 181  
                 {
 182  44
                     finishedConfiguration.setValue( accumulatedValue.toString() );
 183  
                 }
 184  
             }
 185  
 
 186  76
             if ( depth == 0 )
 187  
             {
 188  23
                 result = finishedConfiguration;
 189  
             }
 190  76
         }
 191  
 
 192  
         @Override
 193  
         public void characters(char[] ch, int start, int length) throws SAXException {
 194  69
             String text = new String(ch, start, length);
 195  69
             appendToTopValue(trim ? text.trim() : text);
 196  69
         }
 197  
 
 198  
         private void appendToTopValue(String toAppend) {
 199  
             //noinspection MismatchedQueryAndUpdateOfStringBuilder
 200  69
             StringBuilder stringBuilder = values.get(values.size() - 1);
 201  69
             stringBuilder.append( toAppend);
 202  69
         }
 203  
     }
 204  
 
 205  
 }