/**
* $Id: $
* $Date: $
*
*/
package org.xmlsh.internal.commands;
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 javax.xml.namespace.QName;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLStreamConstants;
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;
import javanet.staxutils.XMLStreamUtils;
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() == XMLStreamConstants.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() == XMLStreamConstants.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.
//