/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Whole Platform 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.lang.xml.visitors;
import static org.whole.lang.xml.reflect.XmlEntityDescriptorEnum.Content;
import org.whole.lang.iterators.IEntityIterator;
import org.whole.lang.iterators.IteratorFactory;
import org.whole.lang.matchers.Matcher;
import org.whole.lang.model.IEntity;
import org.whole.lang.reflect.EntityKinds;
import org.whole.lang.util.EntityUtils;
import org.whole.lang.xml.factories.XmlEntityFactory;
import org.whole.lang.xml.model.CDataSect;
import org.whole.lang.xml.model.Content;
import org.whole.lang.xml.model.Element;
import org.whole.lang.xml.model.IContent;
import org.whole.lang.xml.model.IXmlEntity;
import org.whole.lang.xml.reflect.XmlEntityDescriptorEnum;
import org.whole.lang.xml.util.XmlUtils;
/**
* @author Riccardo Solmi, Enrico Persiani
*/
public class XmlNormalizerVisitor extends XmlTraverseAllVisitor {
@Override
public void visit(CDataSect entity) {
// pack children
if (entity.wSize() > 1) {
IEntityIterator<IEntity> i = IteratorFactory.childIterator();
i.reset(entity);
IEntity first = i.next();
StringBuilder sb = getStringBuilder().append(first.wStringValue());
while (i.hasNext()) {
sb.append(i.next().wStringValue());
i.remove();
}
first.wSetValue(sb.toString());
}
IEntity parent = entity.wGetParent();
if (!EntityUtils.isNull(parent) &&
getBindings().wIsSet("mergeCDataSect") && getBindings().wBooleanValue("mergeCDataSect"))
parent.wSet(entity, XmlEntityFactory.instance.createCharData(entity.wGet(0).wStringValue()));
}
@Override
public void visit(Content entity) {
// recursively normalize nested composite entities
IEntityIterator<IEntity> iterator = IteratorFactory.childMatcherIterator().withPattern(EntityKinds.COMPOSITE);
iterator.reset(entity);
while (iterator.hasNext()) {
IEntity composite = iterator.next();
((IXmlEntity) composite).accept(this);
// move Content's children in place of Content entity
if (Matcher.match(Content, composite)) {
for (int i=composite.wSize()-1; i>=0; i--) {
IEntity child = composite.wGet(i);
composite.wRemove(i);
iterator.add(child);
}
iterator.remove();
}
}
for (int i = 0; i < entity.wSize(); i++) {
IContent child = (IContent) entity.wGet(i);
if (Matcher.matchImpl(XmlEntityDescriptorEnum.CharData, child)) {
IEntity nextChild;
if (i+1 < entity.wSize() && Matcher.matchImpl(XmlEntityDescriptorEnum.CharData, nextChild = entity.wGet(i+1))) {
StringBuilder sb = getStringBuilder();
sb.append(child.wStringValue());
do {
sb.append(nextChild.wStringValue());
entity.wRemove(i+1);
} while (i+1 < entity.wSize() && Matcher.matchImpl(XmlEntityDescriptorEnum.CharData, nextChild = entity.wGet(i+1)));
child.wSetValue(sb.toString());
}
if (XmlUtils.isIgnorableWhitespace(child.wStringValue()))
entity.wRemove(i--);
}
child.accept(this);
}
}
@Override
public void visit(Element entity) {
IContent content = entity.getContent();
if (!EntityUtils.isResolver(content) && !Matcher.match(Content, content)) {
entity.wRemove(content);
entity.setContent(XmlEntityFactory.instance.createContent(content));
}
super.visit(entity);
}
private StringBuilder charDataBuilder;
protected StringBuilder getStringBuilder() {
if (charDataBuilder == null)
charDataBuilder = new StringBuilder(2048);
else
charDataBuilder.setLength(0);
return charDataBuilder;
}
}