我正在开发一个简短的应用程序,它应该从SVN存储库中的项目读出一些元数据。
SVN本身提供了一些命令行工具。其中一个工具是" SVN列表"。如果给出选项--xml,list命令可以传递xml。因此,如果您想要汇总或累积一些数据,您可以使用linux(在我们的示例中为OS)命令。但是,如果您希望拥有不同的数据并且存储库变得更大,那么它就会变得过于复杂和缓慢(从我的角度来看)。
我的解决方案使用JSch建立连接并检索给定存储库路径的xml。下一步是将带有JAXB的xml解组到类中,然后遍历对象(理论上)。
所以我有 - xml
<?xml version="1.0"?>
<lists>
<list
path="<URL>/svn/Repository/<anyProject>/trunk">
</list>
</lists>
xsd
<xsd:complexType name="listsType">
<xsd:sequence>
<xsd:element name="list" type="listType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="listType">
<xsd:sequence>
<xsd:element name="entry" type="entryType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="path" type="xsd:string"/>
</xsd:complexType>
<xsd:complexType name="entryType">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="size" type="xsd:integer" minOccurs="0" maxOccurs="1" />
<xsd:element name="commit" type="commitType"/>
</xsd:sequence>
<xsd:attribute name="kind" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="commitType">
<xsd:sequence>
<xsd:element name="author" type="xsd:string"/>
<xsd:element name="date" type="xsd:dateTime"/>
</xsd:sequence>
<xsd:attribute name="revision" type="xsd:long"/>
</xsd:complexType>
映射的类(指xsd)
但每当我为解组而拍摄时,我都会收到这个例外:
[org.xml.sax.SAXParseException; lineNumber: 6; columnNumber: 9; Content is not allowed in prolog]
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:335)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:563)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:249)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:125)
at my.organisation.repo.util.RepoJaxbUtil.unmarshal(RepoJaxbUtil.java:32)
at my.organisation.repo.util.RepoJaxbUtil.unmarshal(RepoJaxbUtil.java:25)
at my.organisation.repo.tool.RepoFull.start(RepoFull.java:114)
at my.organisation.repo.managing.RepoToolManager.start(RepoToolManager.java:107)
at my.organisation.repo.managing.RepoToolManager.main(RepoToolManager.java:43)
Caused by: org.xml.sax.SAXParseException; lineNumber: 6; columnNumber: 9; Content ist nicht zulässig in angehängtem Abschnitt.
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:203)
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:177)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:400)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:327)
at com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(XMLScanner.java:1472)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$TrailingMiscDriver.next(XMLDocumentScannerImpl.java:1431)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:602)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:505)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:841)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:770)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:643)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:243)
... 8 more
我已经在这里和其他地方进行过很多研究 - 但是从来没有找到关于流程结束的东西(我不天真 - 我知道Streams或Arrays等现在已经结束了流程)
更多细节: 从JSch我收到一个InputStream,它存储在ByteBuffer中:
public ByteBuffer sendCommandForInputStream(String command) {
try {
Channel channel = sesConnection.openChannel("exec");
((ChannelExec) channel).setCommand(command);
InputStream commandOutput = channel.getInputStream();
channel.connect();
byte[] bytes = IOUtils.toByteArray(commandOutput);
ByteBuffer result = ByteBuffer.wrap(bytes);
channel.disconnect();
return result;
}
catch (IOException ioX) {
logWarning(ioX.getMessage());
return null;
}
catch (JSchException jschX) {
logWarning(jschX.getMessage());
return null;
}
}
我必须使用缓冲区,因为如果我在打开它后关闭连接,我不是100%,结果是完整的。
unmarshal方法也需要一个InputStream - 所以我必须&#34;转换&#34;回来了。也许这里把bug放在任何地方:
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.xml.sax.SAXException;
public class RepoJaxbUtil {
public static <T> T unmarshal(ByteBuffer xml, Class<T> clss) throws JAXBException, SAXException, UnsupportedEncodingException {
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(new File("subversionRepo.xsd"));
JAXBContext jaxbContext = JAXBContext.newInstance(clss.getPackage().getName());
InputStream xmlS = newInputStream(xml);
return unmarshal(jaxbContext, schema, xmlS, clss);
}
public static <T> T unmarshal(JAXBContext jaxbContext, Schema schema, InputStream xml, Class<T> clss) throws JAXBException, UnsupportedEncodingException {
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.setSchema(schema);
StreamSource xmlSource = new StreamSource(xml);
return clss.cast(unmarshaller.unmarshal(xmlSource));
}
public static InputStream newInputStream(final ByteBuffer buf) {
return new InputStream() {
public synchronized int read() throws IOException {
if (!buf.hasRemaining()) {
return -1;
}
return buf.get();
}
public synchronized int read(byte[] bytes, int off, int len) throws IOException {
// Read only what's left
len = Math.min(len, buf.remaining());
buf.get(bytes, off, len);
return len;
}
};
}
}
/*(The transfer to a InputSource does not work => just the line from 6 to 7 and the other way around)*/
有人知道如何解决这个问题吗?
答案 0 :(得分:0)
所以我在@lexicore之后找到了一个解决方案(谢谢),说明给定的xml无效。
xml本身是正确的,但JSch Handler类中的处理是不正确的。问题放在RepoJaxbUtil类中的方法'newInputStream(final ByteBuffer buf)'中。在输入流的最后一个字符之后,我设置'-1',这导致了无效的xml内容。
我在JSch SSH Handler中更改了返回类型和名称:
public StringBuffer sendCommandForBuffer(String command) {
StringBuffer outputBuffer = new StringBuffer();
try {
Channel channel = sesConnection.openChannel("exec");
((ChannelExec) channel).setCommand(command);
InputStream commandOutput = channel.getInputStream();
channel.connect();
int readByte = commandOutput.read();
while (readByte != 0xffffffff) {
outputBuffer.append((char) readByte);
readByte = commandOutput.read();
}
return outputBuffer;
}
catch (IOException ioX) {
logWarning(ioX.getMessage());
return null;
}
catch (JSchException jschX) {
logWarning(jschX.getMessage());
return null;
}
}
另一方面,为了简单起见,我回顾了RepoJaxbUtil类并“删除”了线程安全(我很确定这不会导致问题):
public class RepoJaxbUtil {
public static Object unmarshal(StringBuffer xml, Class clss) throws JAXBException, SAXException, UnsupportedEncodingException {
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(new File("subversionRepo.xsd"));
JAXBContext jaxbContext = JAXBContext.newInstance(clss.getPackage().getName());
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.setSchema(schema);
StreamSource source = new StreamSource(new StringReader(xml.toString()));
return unmarshaller.unmarshal(source);
}
}
另一个很重要的建议可能是从JAXBElement到业务逻辑类的调用和转换到目标对象类型(可能它不好 - 但它以我的方式工作):
xmlReturn = instance.sendCommandForBuffer(cmd);
ListsType repoLists;
try {
JAXBElement lt = (JAXBElement) RepoJaxbUtil.unmarshal(xmlReturn, ListsType.class);
LOG.info(lt.toString());
repoLists = (ListsType) lt.getValue();
// any other business logic here
LOG.info("entryCount: " + repoLists.getList().getEntryType().size());
}
catch (JAXBException e) {
LOG.warn("JAXBException occured on project [" + project + "]");
e.printStackTrace();
}
catch (SAXException e) {
LOG.warn("SAXException occured on project [" + project + "]");
e.printStackTrace();
}
catch (UnsupportedEncodingException e) {
LOG.warn("UnsupportedEncodingException occured on project [" + project + "]");
e.printStackTrace();
}