blob: 9635449452128d35c33170e86e7bc27fde13b087 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* 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 com.intellij.xml.actions.xmlbeans;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.XmlRecursiveElementVisitor;
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import com.intellij.psi.meta.PsiMetaData;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlDocument;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.xml.XmlElementDescriptor;
import com.intellij.xml.XmlNSDescriptor;
import com.intellij.xml.impl.schema.XmlNSDescriptorImpl;
import com.intellij.xml.util.XmlUtil;
import org.apache.xmlbeans.*;
import org.apache.xmlbeans.impl.tool.CommandLine;
import org.apache.xmlbeans.impl.xsd2inst.SampleXmlUtil;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.*;
/**
* @author Konstantin Bulenkov
*/
public class Xsd2InstanceUtils {
public static String generate(String[] args) {
Set flags = new HashSet();
Set opts = new HashSet();
flags.add("h");
flags.add("help");
flags.add("usage");
flags.add("license");
flags.add("version");
flags.add("dl");
flags.add("noupa");
flags.add("nopvr");
flags.add("partial");
opts.add("name");
CommandLine cl = new CommandLine(args, flags, opts);
String[] badOpts = cl.getBadOpts();
if (badOpts.length > 0) {
throw new IllegalArgumentException("Unrecognized option: " + badOpts[0]);
}
boolean dl = (cl.getOpt("dl") != null);
boolean nopvr = (cl.getOpt("nopvr") != null);
boolean noupa = (cl.getOpt("noupa") != null);
File[] schemaFiles = cl.filesEndingWith(".xsd");
String rootName = cl.getOpt("name");
if (rootName == null) {
throw new IllegalArgumentException("Required option \"-name\" must be present");
}
// Process Schema files
List sdocs = new ArrayList();
for (File schemaFile : schemaFiles) {
try {
sdocs.add(XmlObject.Factory.parse(schemaFile,
(new XmlOptions()).setLoadLineNumbers().setLoadMessageDigest()));
}
catch (Exception e) {
throw new IllegalArgumentException("Can not load schema file: " + schemaFile + ": " + e.getLocalizedMessage());
}
}
XmlObject[] schemas = (XmlObject[]) sdocs.toArray(new XmlObject[sdocs.size()]);
SchemaTypeSystem sts = null;
if (schemas.length > 0)
{
Collection errors = new ArrayList();
XmlOptions compileOptions = new XmlOptions();
if (dl)
compileOptions.setCompileDownloadUrls();
if (nopvr)
compileOptions.setCompileNoPvrRule();
if (noupa)
compileOptions.setCompileNoUpaRule();
try {
sts = XmlBeans.compileXsd(schemas, XmlBeans.getBuiltinTypeSystem(), compileOptions);
} catch (XmlException e) {
String out = "Schema compilation errors: ";
for (Object error : errors) out += "\n" + error;
throw new IllegalArgumentException(out);
}
}
if (sts == null)
{
throw new IllegalArgumentException("No Schemas to process.");
}
SchemaType[] globalElems = sts.documentTypes();
SchemaType elem = null;
for (SchemaType globalElem : globalElems) {
if (rootName.equals(globalElem.getDocumentElementName().getLocalPart())) {
elem = globalElem;
break;
}
}
if (elem == null) {
throw new IllegalArgumentException("Could not find a global element with name \"" + rootName + "\"");
}
// Now generate it
return SampleXmlUtil.createSampleForType(elem);
}
public static XmlElementDescriptor getDescriptor(XmlTag tag, String elementName) {
final PsiMetaData metaData = tag.getMetaData();
if (metaData instanceof XmlNSDescriptorImpl) {
final XmlNSDescriptorImpl nsDescriptor = (XmlNSDescriptorImpl) metaData;
return nsDescriptor.getElementDescriptor(elementName, nsDescriptor.getDefaultNamespace());
}
return null;
}
public static List<String> addVariantsFromRootTag(XmlTag rootTag) {
PsiMetaData metaData = rootTag.getMetaData();
if (metaData instanceof XmlNSDescriptorImpl) {
XmlNSDescriptorImpl nsDescriptor = (XmlNSDescriptorImpl) metaData;
List<String> elementDescriptors = new ArrayList<String>();
XmlElementDescriptor[] rootElementsDescriptors = nsDescriptor.getRootElementsDescriptors(PsiTreeUtil.getParentOfType(rootTag, XmlDocument.class));
for(XmlElementDescriptor e:rootElementsDescriptors) {
elementDescriptors.add(e.getName());
}
return elementDescriptors;
}
return Collections.emptyList();
}
public static String processAndSaveAllSchemas(@NotNull XmlFile file, @NotNull final Map<String, String> scannedToFileName,
final @NotNull SchemaReferenceProcessor schemaReferenceProcessor) {
final String fileName = file.getName();
String previous = scannedToFileName.get(fileName);
if (previous != null) return previous;
scannedToFileName.put(fileName, fileName);
final StringBuilder result = new StringBuilder();
file.acceptChildren(new XmlRecursiveElementVisitor() {
@Override public void visitElement(PsiElement psiElement) {
super.visitElement(psiElement);
if (psiElement instanceof LeafPsiElement) {
final String text = psiElement.getText();
result.append(text);
}
}
@Override public void visitXmlAttribute(XmlAttribute xmlAttribute) {
boolean replaced = false;
if (xmlAttribute.isNamespaceDeclaration()) {
replaced = true;
final String value = xmlAttribute.getValue();
result.append(xmlAttribute.getText()).append(" ");
if (!scannedToFileName.containsKey(value)) {
final XmlNSDescriptor nsDescriptor = xmlAttribute.getParent().getNSDescriptor(value, true);
if (nsDescriptor != null) {
processAndSaveAllSchemas(nsDescriptor.getDescriptorFile(), scannedToFileName, schemaReferenceProcessor);
}
}
} else if ("schemaLocation".equals(xmlAttribute.getName())) {
final PsiReference[] references = xmlAttribute.getValueElement().getReferences();
if (references.length > 0) {
PsiElement psiElement = references[0].resolve();
if (psiElement instanceof XmlFile) {
final String s = processAndSaveAllSchemas(((XmlFile) psiElement), scannedToFileName, schemaReferenceProcessor);
if (s != null) {
result.append(xmlAttribute.getName()).append("='").append(s).append('\'');
replaced = true;
}
}
}
}
if (!replaced) result.append(xmlAttribute.getText());
}
});
final VirtualFile virtualFile = file.getVirtualFile();
final String content = result.toString();
byte[] bytes;
if (virtualFile != null) {
bytes = content.getBytes(virtualFile.getCharset());
} else {
try {
final String charsetName = XmlUtil.extractXmlEncodingFromProlog(content.getBytes());
bytes = charsetName != null ? content.getBytes(charsetName) : content.getBytes();
} catch (UnsupportedEncodingException e) {
bytes = content.getBytes();
}
}
schemaReferenceProcessor.processSchema(fileName, bytes);
return fileName;
}
public interface SchemaReferenceProcessor {
void processSchema(String schemaFileName, byte[] schemaContent);
}
}