blob: e86644865f8f65fba4c73596da273977d520954e [file] [log] [blame]
/* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.xmlbeans.impl.store;
import org.apache.xmlbeans.impl.common.ValidatorListener;
import javax.xml.stream.Location;
import org.apache.xmlbeans.XmlCursor;
import javax.xml.namespace.QName;
final class Validate implements ValidatorListener.Event
{
Validate ( Cur c, ValidatorListener sink )
{
if (!c.isUserNode())
throw new IllegalStateException( "Inappropriate location to validate" );
_sink = sink;
_cur = c;
_textCur = c.tempCur();
_hasText = false;
_cur.push();
try
{
process();
}
finally
{
_cur.pop();
_cur = null;
_sink = null;
_textCur.release();
}
}
private void process ( )
{
emitEvent( ValidatorListener.BEGIN );
if (_cur.isAttr())
{
// If validating an attr, I'm really validating the contents of that attr. So, go to
// any text value and shove it thru the validator.
_cur.next();
if (_cur.isText())
emitText();
}
else
{
assert _cur.isContainer();
// Do the attrs of the top container
doAttrs();
for ( _cur.next() ; ! _cur.isAtEndOfLastPush() ; _cur.next() )
{
switch ( _cur.kind() )
{
case Cur.ELEM :
emitEvent( ValidatorListener.BEGIN );
doAttrs();
break;
case - Cur.ELEM :
emitEvent( ValidatorListener.END );
break;
case Cur.TEXT :
emitText();
break;
case Cur.COMMENT :
case Cur.PROCINST :
_cur.toEnd();
break;
default :
throw new RuntimeException( "Unexpected kind: " + _cur.kind() );
}
}
}
emitEvent( ValidatorListener.END );
}
private void doAttrs ( )
{
// When processing attrs, there can be no accumulated text because there would have been
// a preceeding event which would have flushged the text.
assert !_hasText;
if (_cur.toFirstAttr())
{
do
{
if (_cur.isNormalAttr() && !_cur.getUri().equals( Locale._xsi ))
_sink.nextEvent( ValidatorListener.ATTR, this );
}
while ( _cur.toNextAttr() );
_cur.toParent();
}
_sink.nextEvent( ValidatorListener.ENDATTRS, this );
}
private void emitText ( )
{
assert _cur.isText();
if (_hasText)
{
if (_oneChunk)
{
if (_textSb == null)
_textSb = new StringBuffer();
else
_textSb.delete( 0, _textSb.length() );
assert _textCur.isText();
CharUtil.getString(
_textSb, _textCur.getChars( -1 ), _textCur._offSrc, _textCur._cchSrc );
_oneChunk = false;
}
assert _textSb != null && _textSb.length() > 0;
CharUtil.getString( _textSb, _cur.getChars( -1 ), _cur._offSrc, _cur._cchSrc );
}
else
{
_hasText = true;
_oneChunk = true;
_textCur.moveToCur( _cur );
}
}
private void emitEvent ( int kind )
{
assert kind != ValidatorListener.TEXT;
assert kind != ValidatorListener.ATTR || !_hasText;
assert kind != ValidatorListener.ENDATTRS || !_hasText;
if (_hasText)
{
_sink.nextEvent( ValidatorListener.TEXT, this );
_hasText = false;
}
_sink.nextEvent( kind, this );
}
public String getText ( )
{
if (_cur.isAttr())
return _cur.getValueAsString();
assert _hasText;
assert _oneChunk || (_textSb != null && _textSb.length() > 0);
assert !_oneChunk || _textCur.isText();
return _oneChunk ? _textCur.getCharsAsString() : _textSb.toString();
}
public String getText ( int wsr )
{
if (_cur.isAttr())
return _cur.getValueAsString( wsr );
assert _hasText;
assert _oneChunk || (_textSb != null && _textSb.length() > 0);
assert !_oneChunk || _textCur.isText();
if (_oneChunk)
return _textCur.getCharsAsString( wsr );
return Locale.applyWhiteSpaceRule( _textSb.toString(), wsr );
}
public boolean textIsWhitespace ( )
{
if (_cur.isAttr())
{
return
_cur._locale.getCharUtil().isWhiteSpace(
_cur.getFirstChars(), _cur._offSrc, _cur._cchSrc );
}
assert _hasText;
if (_oneChunk)
{
return
_cur._locale.getCharUtil().isWhiteSpace(
_textCur.getChars( -1 ), _textCur._offSrc, _textCur._cchSrc );
}
String s = _textSb.toString();
return _cur._locale.getCharUtil().isWhiteSpace( s, 0, s.length() );
}
public String getNamespaceForPrefix ( String prefix )
{
return _cur.namespaceForPrefix( prefix, true );
}
public XmlCursor getLocationAsCursor ( )
{
return new Cursor( _cur );
}
public Location getLocation ( )
{
return null;
}
public String getXsiType ( )
{
return _cur.getAttrValue( Locale._xsiType );
}
public String getXsiNil ( )
{
return _cur.getAttrValue( Locale._xsiNil );
}
public String getXsiLoc ( )
{
return _cur.getAttrValue( Locale._xsiLoc );
}
public String getXsiNoLoc ( )
{
return _cur.getAttrValue( Locale._xsiNoLoc );
}
public QName getName ( )
{
return _cur.isAtLastPush() ? null : _cur.getName();
}
//
//
//
private ValidatorListener _sink;
private Cur _cur;
// Two ways to accumulate text. First, I can have a Cur positioned at the text. I do this
// instead of getting the there there because white space rules are applied at a later point.
// This way, when I turn the text into a String, I can cache the string. If multiple chunks
// of text exists for one event, then I accumulate all the text into a string buffer and I,
// then, don't care about caching Strings.
private boolean _hasText;
private boolean _oneChunk;
private Cur _textCur;
private StringBuffer _textSb;
}