/**
* $Id: $
* $Date: $
*
*/
package org.xmlsh.commands.internal;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
import javanet.staxutils.XMLStreamUtils;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import org.xmlsh.core.Options;
import org.xmlsh.core.XCommand;
import org.xmlsh.core.XValue;
import org.xmlsh.sh.shell.SerializeOpts;
import org.xmlsh.util.Util;
public class xaddbase extends XCommand {
private XMLEventFactory mFactory = XMLEventFactory.newInstance();
private static QName mBaseQName = new QName("http://www.w3.org/XML/1998/namespace","base" , "xml");
@Override
public int run( List<XValue> args )
throws Exception
{
boolean opt_all = false ;
boolean opt_relative = false ;
Options opts = new Options( "a=all,r=relative" , SerializeOpts.getOptionDefs() );
opts.parse(args);
SerializeOpts serializeOpts = getSerializeOpts(opts);
XMLEventReader reader = getStdin().asXMLEventReader(serializeOpts);
XMLEventWriter writer = getStdout().asXMLEventWriter(serializeOpts);
opt_all = opts.hasOpt("all");
opt_relative = opts.hasOpt("relative");
add_base( reader , writer , opt_all , opt_relative , getStdin().getSystemId() );
return 0;
}
private XMLEvent add_base_attr( StartElement start , String base)
{
Attribute attr = mFactory.createAttribute(mBaseQName, base);
return XMLStreamUtils.mergeAttributes(start, Collections.singletonList(attr).iterator(), mFactory);
}
private String resolve(String parentBaseURI, String baseURI, boolean opt_relative) throws URISyntaxException {
if(! opt_relative )
return baseURI ;
if( Util.isBlank(parentBaseURI))
return baseURI;
URI u = new URI( parentBaseURI );
// Remove final path component from parent
String path = u.getPath();
int slash = path.lastIndexOf('/');
if( slash >= 0 )
path = path.substring(0,slash);
URI parent_URI =
new URI(u.getScheme(),
u.getUserInfo(), u.getHost(), u.getPort(),
path,
u.getQuery(),
u.getFragment());
URI base_URI = new URI( baseURI );
URI relative = parent_URI.relativize(base_URI);
return relative.toString();
}
private void add_base(XMLEventReader reader, XMLEventWriter writer, boolean opt_all, boolean opt_relative , String parentURI ) throws URISyntaxException, XMLStreamException
{
Stack<String> mURIs = new Stack<String>();
mURIs.push(parentURI);
while( reader.hasNext() ){
XMLEvent event = reader.nextEvent();
if( event.getEventType() == XMLEvent.START_ELEMENT){
boolean addBase = false ;
StartElement start = event.asStartElement();
String baseURI = getBaseURI(start );
parentURI = mURIs.lastElement() ;
boolean bIsRoot =mURIs.size() == 1;
if( bIsRoot ){ // document root
// First element - always set the xml:base attribute
addBase = true ;
}
else
if( opt_all )
addBase = true ;
else
if( baseURI.equals(parentURI))
addBase = false ;
else
if( !Util.isEqual(parentURI, baseURI))
addBase = true;
if( addBase ){
String uri = resolve( parentURI , baseURI , bIsRoot ? false : opt_relative);
event = add_base_attr(start,uri);
}
else
event = removeBase( start );
mURIs.push(baseURI);
}
else
if( event.getEventType() == XMLEvent.END_ELEMENT)
mURIs.pop();
writer.add(event);
}
}
private String getBaseURI(StartElement start)
{
Attribute baseAttr = start.getAttributeByName( mBaseQName );
if( baseAttr != null )
return baseAttr.getValue();
String systemID = start.getLocation().getSystemId();
if( Util.isBlank(systemID))
return "";
return systemID ;
}
@SuppressWarnings("unchecked")
private XMLEvent removeBase(StartElement start) {
if( start.getAttributeByName(mBaseQName) != null ){
Iterator iter = start.getAttributes();
while( iter.hasNext()){
Attribute a = (Attribute) iter.next();
if( a.getName().equals(mBaseQName) )
iter.remove();
}
}
return start ;
}
}
//
//
//Copyright (C) 2008-2014 David A. Lee.
//
//The contents of this file are subject to the "Simplified BSD License" (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.opensource.org/licenses/bsd-license.php
//
//Software distributed under the License is distributed on an "AS IS" basis,
//WITHOUT WARRANTY OF ANY KIND, either express or implied.
//See the License for the specific language governing rights and limitations under the License.
//
//The Original Code is: all this file.
//
//The Initial Developer of the Original Code is David A. Lee
//
//Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
//
//Contributor(s): none.
//