2013-03-05 2 views
3

У меня есть строковое представление некоторого XML, и я хочу запустить XQuery на нем в памяти. Я играл с Саксоном и придумал решение, но чтобы он работал, я сделал уродливую, уродливую вещь. У меня такое чувство, что из-за моего отсутствия опыта с Саксоном. Вот код, который работает:Как запустить XQuery против XML в String?

import javax.xml.transform.URIResolver; 
import net.sf.saxon.Configuration; 
import net.sf.saxon.s9api.*; 

public class XmlTest { 
    public static void main(String[] args) { 
    try { 
     final String tableXml = 
     "<table>" + 
     " <columns>" + 
     " <column>Foo</column><column>Bar</column>" + 
     " </columns>" + 
     " <rows>" + 
     " <row><cell>Foo1</cell><cell>Bar1</cell></row>" + 
     " <row><cell>Foo2</cell><cell>Bar2</cell></row>" + 
     " </rows>" + 
     "</table>"; 

     Configuration saxonConfig = new Configuration(); 
     Processor processor = new Processor(saxonConfig); 

     XQueryCompiler xqueryCompiler = processor.newXQueryCompiler(); 
     XQueryExecutable xqueryExec = xqueryCompiler 
       .compile("<result>{" 
         + "doc('')/table/rows/row/cell/text()='Foo2'" 
         + "}</result>"); 

     XQueryEvaluator xqueryEval = xqueryExec.load(); 
     xqueryEval.setSource(new SAXSource(new InputSource(
      new StringReader(tableXml)))); 

     XdmDestination destination = new XdmDestination(); 

     xqueryEval.setDestination(destination); 

     // Avert your eyes! 
     xqueryEval.setURIResolver(new URIResolver() { 
     @Override 
     public Source resolve(String href, String base) throws TransformerException { 
      return new StreamSource(new StringReader(tableXml)); 
     } 
     }); 

     xqueryEval.run(); 

     System.out.println(destination.getXdmNode()); 

    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    } 
} 

Проблема, с которой я столкнулся, была связана с базовым URI документа XML. Поскольку это было в памяти, базового документа для ссылки не было. Я знаю, что XML всегда будет самодостаточным, поэтому я решил переопределить URIResolver, чтобы просто передать XML, завернутый в объект типа Source. Я знаю, что это неправильно, но это работает. Если я этого не сделаю, я получаю ошибку Content not allowed in prolog. Из остальной части сообщения об ошибке похоже, что он пытается читать в текущем каталоге как XML-файл. Эта часть немного загадочна для меня, но я хочу учиться! Есть ли правильный способ делать то, что я хочу сделать?

ответ

4

Если вы хотите получить доступ к исходному документу с помощью doc (''), то это способ сделать это. Однако это намного проще, если вы пишете свой запрос для доступа к исходному документу в качестве значения элемента контекста. Таким образом, вы измените запрос

"<result>{/table/rows/row/cell='Foo2'}</result>" 

Вы уже поставляли элемент контекста, используя setSource(), даже если вы не используете его, так что это единственное изменение, которое вы должны сделать.

(Я также вырезал «/ text()» из запроса, потому что гораздо лучше проверить значение элемента непосредственно - это означает, что ваш запрос будет работать, если исходный документ содержит комментарии).

+2

Ах! Таким образом, вызов для решения URI был вызван ссылкой на 'doc (" ")'. Я изначально написал запрос без него, но добавил его как попытку исправить ошибку, которую я получал (которая теперь забыта). Он остался, потому что я чувствовал, что он улучшил ситуацию, но теперь я вижу, что это была красная селедка. Без ссылки на 'doc()' я могу удалить мою рискованную реализацию URIResolver, и все работает правильно. Спасибо, Майкл. –

0

Можете ли вы сделать это без включения и размещения только вывода xquery в эту финальную строку?

Смежные вопросы