java - 使用 Saxon/XQuery 设置 URI 或目录解析器

标签 java xquery saxon

我正在用 Java 开发一个简单的命令行应用程序,用于从大型 XML 数据集(15,000 多个 XML 文件)中挖掘数据。为此,我选择使用 Saxon S9API 作为 XQuery 处理器。只要有对互联网的开放访问,Saxon 使用的解析器可以解析 xsi:noNamespaceSchemaLocation URI(或我假设的任何其他内容),一切就可以正常工作。

我在 Stackoverflow 以及一般的 Google 搜索中进行了搜索,寻找有关如何向 XQuery 处理器提供目录的答案。我还没有找到关于如何执行此操作的良好解释。

这是我目前拥有的简单代码,正如我所说,当互联网开放时,它可以正常工作:


    package ipd.part.info.mining.app;

    import java.io.File;
    import java.util.List;
    import java.util.Scanner;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import javax.xml.parsers.ParserConfigurationException;
    import javax.xml.transform.Transformer;
    import javax.xml.transform.TransformerException;
    import javax.xml.transform.dom.DOMSource;
    import javax.xml.transform.stream.StreamResult;
    import net.sf.saxon.Configuration;
    import net.sf.saxon.TransformerFactoryImpl;
    import net.sf.saxon.s9api.DOMDestination;
    import net.sf.saxon.s9api.Processor;
    import net.sf.saxon.s9api.QName;
    import net.sf.saxon.s9api.SaxonApiException;
    import net.sf.saxon.s9api.XQueryCompiler;
    import net.sf.saxon.s9api.XQueryEvaluator;
    import net.sf.saxon.s9api.XQueryExecutable;
    import net.sf.saxon.s9api.XdmAtomicValue;
    import net.sf.saxon.lib.*;
    import static org.apache.xerces.jaxp.JAXPConstants.JAXP_SCHEMA_LANGUAGE;
    import static org.apache.xerces.jaxp.JAXPConstants.W3C_XML_SCHEMA;
    import org.apache.xerces.util.XMLCatalogResolver;
    import org.apache.xml.resolver.tools.CatalogResolver;
    import org.w3c.dom.Document;
    import org.xml.sax.ErrorHandler;

    /**
     *
     * @author tfurst
     */
    public class IPDPartInfoMiningApp {

        /**
         * @param args the command line arguments
         */
        private static Scanner scanner = new Scanner(System.in);
        private static String ietmPath;
        private static String outputPath;

        private static CatalogResolver resolver;
        private static org.apache.xerces.util.XMLCatalogResolver xres;
        private static ErrorHandler eHandler;

        private static DocumentBuilderFactory DBF;
        private static DocumentBuilder DB;

        public static void main(String[] args) {
            initDb();
            try {
                // TODO code application logic here
                System.out.println("Enter path to complete IETM Export:");
                ietmPath = scanner.nextLine();
                System.out.println("Enter path to save report:");
                outputPath = scanner.nextLine();

                Processor proc = new Processor(true);

                XQueryCompiler comp = proc.newXQueryCompiler();

                //File xq = fixXquery(new File(XQ));
                //XQueryExecutable exp = comp.compile(xq);
                XQueryExecutable exp = comp.compile("declare variable $path external;\n" +
    "\n" +
    "let $coll := collection(concat($path,'?select=*.xml'))//itemSequenceNumber \n" +
    "\n" +
    "return\n" +
    "<parts>\n" +
    "{\n" +
    "    for $mod in $coll\n" +
    "    let $pn := normalize-space($mod/partNumber)\n" +
    "    let $nomen := $mod/partIdentSegment[1]/descrForPart\n" +
    "    let $smr := $mod/locationRcmdSegment/locationRcmd/sourceMaintRecoverability\n" +
    "    order by $pn\n" +
    "    return <part pn=\"{$pn}\" nomen=\"{$nomen}\" smr=\"{$smr}\"/>\n" +
    "}\n" +
    "</parts>");
                //Serializer out = proc.newSerializer(System.out);

                Document dom = DB.newDocument();

                XQueryEvaluator ev = exp.load();
                ev.setExternalVariable(new QName("path"), new XdmAtomicValue(new File(ietmPath).toPath().toUri().toString().substring(0, new File(ietmPath).toPath().toUri().toString().lastIndexOf("/"))));
                ev.run(new DOMDestination(dom));

                TransformerFactoryImpl tfact = new net.sf.saxon.TransformerFactoryImpl();

                Transformer trans = tfact.newTransformer();
                DOMSource src = new DOMSource(dom);
                StreamResult res = new StreamResult(new File(outputPath + File.separator + "output.xml"));
                trans.transform(src, res);


            } catch (SaxonApiException | TransformerException ex) {
                Logger.getLogger(IPDPartInfoMiningApp.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        private static XMLCatalogResolver createXMLCatalogResolver(CatalogResolver resolver)
        {
            int i = 0;

            List files = resolver.getCatalog().getCatalogManager().getCatalogFiles();
            String[] catalogs = new String[files.size()];
            XMLCatalogResolver xcr = new XMLCatalogResolver();

            for(Object file : files)
            {
                catalogs[i] = new File(file.toString()).getAbsolutePath();
            }

            xcr.setCatalogList(catalogs);
            return xcr;
        }

        private static void initDb()
        {
            try 
            {
                resolver = new CatalogResolver();
                eHandler = new DocumentErrorHandler();
                xres = createXMLCatalogResolver(resolver);
                DBF = DocumentBuilderFactory.newInstance();
                DBF.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
                DBF.setNamespaceAware(true);
                DB = DBF.newDocumentBuilder();
                DB.setEntityResolver(xres);
                DB.setErrorHandler(eHandler);
            } 
            catch (ParserConfigurationException ex) 
            {
                ex.printStackTrace();
            }
        }

    }

当我断开计算机与网络的连接时,我收到此错误:

C:\Users\tfurst\Desktop\XQuery Test\testXml\test\tool>java -jar IPD_Part_Info_Mining_App.jar
Enter path to complete IETM Export:
C:\Users\tfurst\Desktop\Wire Repl Testing
Enter path to save report:
C:\Users\tfurst\Desktop\Wire Repl Testing\report
Error on line 6 column 2
  collection(): failed to parse XML file
  file:/C:/Users/tfurst/Desktop/Wire%20Repl%20Testing/DMC-HH60W-A-52-21-0001-04AAA-520A-B.xml: I/O error reported by XML parser processing file:/C:/Users/tfurst/Desktop/Wire%20Repl%20Testing/DMC-HH60W-A-52-21-0001-04AAA-520A-B.xml: Read timed out
Aug 20, 2019 2:55:23 PM ipd.part.info.mining.app.IPDPartInfoMiningApp main
SEVERE: null
net.sf.saxon.s9api.SaxonApiException: collection(): failed to parse XML file file:/C:/Users/tfurst/Desktop/Wire%20Repl%20Testing/DMC-HH60W-A-52-21-0001-04AAA-520A-B.xml: I/O error reported by XML parser processing file:/C:/Users/tfurst/Desktop/Wire%20Repl%20Testing/DMC-HH60W-A-52-21-0001-04AAA-520A-B.xml: Read timed out
        at net.sf.saxon.s9api.XQueryEvaluator.run(XQueryEvaluator.java:372)
        at ipd.part.info.mining.app.IPDPartInfoMiningApp.main(IPDPartInfoMiningApp.java:80)
Caused by: net.sf.saxon.trans.XPathException: collection(): failed to parse XML file file:/C:/Users/tfurst/Desktop/Wire%20Repl%20Testing/DMC-HH60W-A-52-21-0001-04AAA-520A-B.xml: I/O error reported by XML parser processing file:/C:/Users/tfurst/Desktop/Wire%20Repl%20Testing/DMC-HH60W-A-52-21-0001-04AAA-520A-B.xml: Read timed out
        at net.sf.saxon.resource.XmlResource.getItem(XmlResource.java:113)
        at net.sf.saxon.functions.CollectionFn$2.mapItem(CollectionFn.java:246)
        at net.sf.saxon.expr.ItemMappingIterator.next(ItemMappingIterator.java:113)
        at net.sf.saxon.expr.ItemMappingIterator.next(ItemMappingIterator.java:108)
        at net.sf.saxon.expr.ItemMappingIterator.next(ItemMappingIterator.java:108)
        at net.sf.saxon.om.FocusTrackingIterator.next(FocusTrackingIterator.java:85)
        at net.sf.saxon.expr.ContextMappingIterator.next(ContextMappingIterator.java:59)
        at net.sf.saxon.expr.sort.DocumentOrderIterator.<init>(DocumentOrderIterator.java:47)
        at net.sf.saxon.expr.sort.DocumentSorter.iterate(DocumentSorter.java:230)
        at net.sf.saxon.expr.flwor.ForClausePush.processTuple(ForClausePush.java:34)
        at net.sf.saxon.expr.flwor.FLWORExpression.process(FLWORExpression.java:841)
        at net.sf.saxon.expr.instruct.ElementCreator.processLeavingTail(ElementCreator.java:337)
        at net.sf.saxon.expr.instruct.ElementCreator.processLeavingTail(ElementCreator.java:284)
        at net.sf.saxon.expr.instruct.Instruction.process(Instruction.java:151)
        at net.sf.saxon.query.XQueryExpression.run(XQueryExpression.java:411)
        at net.sf.saxon.s9api.XQueryEvaluator.run(XQueryEvaluator.java:370)
        ... 1 more


C:\Users\tfurst\Desktop\XQuery Test\testXml\test\tool>pause
Press any key to continue . . .

我确信这可能是一个相对简单的修复,很可能是我忽略的。我知道如何在处理 XSL 转换时通过提供目录和模式位置来处理这个问题。预先感谢您的帮助,非常感谢。

最佳答案

要使用 XML 目录文件,代码中类似以下内容应该有效:

        Processor proc = new Processor(false); //false for Saxon-HE
        XQueryCompiler compiler = proc.newXQueryCompiler();
        XmlCatalogResolver.setCatalog("path/catalog.xml", proc.getUnderlyingConfiguration(), false);
        ...

关于java - 使用 Saxon/XQuery 设置 URI 或目录解析器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57589766/

相关文章:

xquery - 如何在XQuery中找到两个节点的最低公共(public)祖先?

java - 验证 "Invalid byte 1 of 1-byte UTF-8 sequence."中的 XML 文档结果

xml - 使用单个 XSL 流将一个大型 XML 文件拆分为多个文件

java - Java中将一长串日期和时间转换为时间戳格式

xquery - 用于目录查询的 Marklogic Rest API

java - Aeron 基本 pub/sub 对在同一主机上连接,跨主机失败

xquery - 在 MarkLogic 中搜索 XML 文档以获取处理指令

java - Saxon 免费版本中的 XQuery

java - Selenium Grid,如何将 WebDriver 与 ThreadSafeSeleniumSessionStorage.session() 一起使用

java - 可以在主类中初始化所有类吗?