2011-04-14 5 views
3

books.xml 저자 이름과 책 제목이있는 파일이 있습니다. 다음 코드 스 니펫을 사용하여 books.xml을 쿼리합니다.XPath 쿼리에서 Java 문자열 변수를 사용하는 방법

XPathFactory factory = XPathFactory.newInstance(); 
XPath xpath = factory.newXPath(); 
XPathExpression expr 
    = xpath.compile("//book[author= 'Larry Niven']/title/text()"); 

이제 프로그램에서 String 변수로 실행하는 동안 전달하려는 경우 쿼리에 직접 이름을 입력하는 대신 수행 할 방법입니다. 문자열 변수 이름을 넣는 것만으로는 효과가 없습니다!

+0

xpath 표현식을 동적으로 빌드 할 수없는 이유는 무엇입니까? "// book [author = '"+ authorName + "']/title/text()와 같은 의미입니까? –

+0

예. 좋은 시작 방법입니다. 아프다. 감사. – JavaBits

+0

XPath 평가 컨텍스트에 변수를 등록하는 방법은 XPath 엔진 API에 전적으로 달려 있습니다. –

답변

-2
String rawXPath = "//book[author= '" + larrysName + "']/title/text()"; 

또는 larrysName 어딘가에서 오는 유형 String의 변수입니다

String rawXPath = String.format("//book[author= '%s']/title/text()", larrysName); 

.

+0

감사합니다. 완벽하게 작동합니다. – JavaBits

+2

-1 불행히도 _O'Hara_ 또는 따옴표가 포함 된 다른 텍스트와 같은 이름에는 완벽하게 작동하지 않습니다. – McDowell

+1

@McDowell : 좋은 지적입니다. – khachik

6

여기서 문제 당신은 악명 높은 래리 "깡패"O'Niven 같은 저자가있을 때 . 이 경우

,이 순진한 구현으로, 변수를 탈출해야합니다

String xml = 
    "<xml><foo bar=\"Larry &quot;Basher&quot; O'Niven\">Ringworm</foo></xml>"; 
String query = 
    String.format("//foo[@bar=%s]", escape("Larry \"Basher\" O'Niven")); 
System.out.println(query); 
String book = XPathFactory.newInstance() 
    .newXPath() 
    .evaluate(query, new InputSource(new StringReader(xml))); 
System.out.println(query + " > " + book); 
+0

도움이 될 것이라고 확신합니다. – JavaBits

4

당신은 사실을 모두 사용할 수 있습니다

public static String escape(String s) { 
    Matcher matcher = Pattern.compile("['\"]") 
     .matcher(s); 
    StringBuilder buffer = new StringBuilder("concat("); 
    int start = 0; 
    while (matcher.find()) { 
     buffer.append("'") 
      .append(s.substring(start, matcher.start())) 
      .append("',"); 
     buffer.append("'".equals(matcher.group()) ? "\"'\"," : "'\"',"); 
     start = matcher.end(); 
    } 
    if (start == 0) { 
     return "'" + s + "'"; 
    } 
    return buffer.append("'") 
     .append(s.substring(start)) 
     .append("'") 
     .append(")") 
     .toString(); 
    } 

이이 코드를 입증 할 수 XPath의 커스텀 함수와 변수들 - 그러나 빠른 해킹은 많은 용도에 대해 더 생산적 일 수 있습니다.

다음은 내가 학생들을위한 학습 도구로 개발 한 코드입니다. 이 작업을 수행 할 수 있습니다.

// create some variable we want to use in the xpath 
xPathVariableAndFunctionResolver.newVariable("myNamespace", "id", "xs:string", "l2"); // myNamespace is declared in the namespace context with prefix 'my' 

// create an XPath expression 
String expression = "//did:Component[@id=$my:id]"; // variable $namespace:name 
XPathExpression findComponents = xPathFunctionAndVariableOperator.compile(expression); 

// execute the XPath expression against the document 
NodeList statements = (NodeList)findComponents.evaluate(document, XPathConstants.NODESET); 

그리고 XPath 기능과 거의 동일합니다. 코드, 일반의 XPath evalutation에 대한 최초의 래퍼 :

public class XPathOperator { 

    protected XPath xPath; 
    protected XPathFactory xPathFactory; 

    private Hashtable<String, XPathExpression> compiled = new Hashtable<String, XPathExpression>(); 

    protected void initFactory() throws XPathFactoryConfigurationException { 
     xPathFactory = XPathFactory.newInstance(XPathConstants.DOM_OBJECT_MODEL); 
    } 

    protected void initXPath(NamespaceContext context) { 
     xPath = xPathFactory.newXPath(); 
     xPath.setNamespaceContext(context); 
    } 

    public XPathOperator(NamespaceContext context) throws XPathFactoryConfigurationException { 
     initFactory(); 
     initXPath(context); 
    } 

    public Object evaluate(Document document, String expression, QName value) throws XPathExpressionException { 

     // create an XPath expression - http://www.zvon.org/xxl/XPathTutorial/General/examples.html 
     XPathExpression findStatements = compile(expression); 

     // execute the XPath expression against the document 
     return (NodeList)findStatements.evaluate(document, value); 
    } 

    public XPathExpression compile(String expression) throws XPathExpressionException { 
     if(compiled.containsKey(expression)) { 
      return (XPathExpression) compiled.get(expression); 
     } 

     XPathExpression xpath = xPath.compile(expression); 

     System.out.println("Compiled XPath " + expression); 

     compiled.put(expression, xpath); 

     return xpath; 
    } 
} 

그런 다음 우리가 네임 스페이스 물론, 사용자 정의 변수와 함수의 개념을 추가 :

public class XPathFunctionAndVariableOperator extends XPathOperator { 

     public XPathFunctionAndVariableOperator(NamespaceContext context, XPathVariableResolver xPathVariableResolver, XPathFunctionResolver xPathFunctionResolver) throws XPathFactoryConfigurationException { 

    super(context); 

     xPath.setXPathVariableResolver(xPathVariableResolver); 
     xPath.setXPathFunctionResolver(xPathFunctionResolver); 
    } 
} 

를 빼고 재미 없을 것이다 변수와 기능 리졸버 :

public class XPathVariableAndFunctionResolver implements XPathVariableResolver, XPathFunctionResolver { 

    private Hashtable functions = new Hashtable(); 
    private Hashtable variables = new Hashtable(); 

    private SchemaDVFactory factory = SchemaDVFactory.getInstance(); 

    public XPathFunction resolveFunction(QName functionName, int arity) { 
     Hashtable table = (Hashtable)functions.get(functionName.getNamespaceURI()); 
     if(table != null) { 
      XPathFunction function = (XPathFunction)table.get(functionName.getLocalPart()); 
      if(function == null) { 
       throw new RuntimeException("Function " + functionName.getLocalPart() + " does not exist in namespace " + functionName.getNamespaceURI() + "!"); 
      } 
      System.out.println("Resolved function " + functionName + " with " + arity + " argument(s)"); 
      return function; 
     } 
     throw new RuntimeException("Function namespace " + functionName.getNamespaceURI() + " does not exist!"); 
    } 

    /** 
    * 
    * Adds a variable using namespace and name, primitive type and default value 
    * 
    * @param namespace 
    * @param name 
    * @param datatype  one of the built-in XML datatypes 
    * @param value 
    * @throws InvalidDatatypeValueException if value is not of correct datatype 
    */ 

    @SuppressWarnings("unchecked") 
    public void newVariable(String namespace, String name, String datatype, String value) throws InvalidDatatypeValueException { 

     int index = datatype.indexOf(":"); 
     if(index != -1) { 
      datatype = datatype.substring(index+1); 
     } 
     XSSimpleType builtInType = factory.getBuiltInType(datatype); 

     if(builtInType == null) { 
      throw new RuntimeException("Null type for " + datatype); 
     } 

     ValidationState validationState = new ValidationState(); 
     ValidatedInfo validatedInfo = new ValidatedInfo(); 

     builtInType.validate(value, validationState, validatedInfo); 

     System.out.println("Defined variable " + name + " as " + datatype + " with value " + value); 

     Hashtable table; 
     if(!variables.containsKey(namespace)) { 
      table = new Hashtable(); 
      variables.put(namespace, table); 
     } else { 
      table = (Hashtable)variables.get(namespace); 
     } 

     table.put(name, new Object[]{validatedInfo, builtInType}); 
    } 

    public void newVariableValue(String namespace, String name, String value) throws InvalidDatatypeValueException { 
     ValidationState validationState = new ValidationState(); 

     Hashtable table; 
     if(!variables.containsKey(namespace)) { 
      throw new RuntimeException("Unknown variable namespace " + namespace); 
     } else { 
      table = (Hashtable)variables.get(namespace); 
     } 

     Object[] bundle = (Object[])table.get(name); 
     ValidatedInfo validatedInfo = (ValidatedInfo)bundle[0]; 
     XSSimpleType builtInType = (XSSimpleType)bundle[1]; 
     builtInType.validate(value, validationState, validatedInfo); // direct reference transfer of value 

     System.out.println("Assigned value " + validatedInfo.normalizedValue + " to variable " + name); 
    } 

    public Object resolveVariable(QName variableName) { 

     Hashtable table; 
     if(!variables.containsKey(variableName.getNamespaceURI())) { 
      throw new RuntimeException("Unknown variable namespace " + variableName.getNamespaceURI()); 
     } else { 
      table = (Hashtable)variables.get(variableName.getNamespaceURI()); 
     } 

     Object[] bundle = (Object[])table.get(variableName.getLocalPart()); 
     if(bundle != null) { 
      ValidatedInfo var = (ValidatedInfo)bundle[0]; 

      if(var != null) { 
       switch(var.actualValueType) { // some types omitted, customize your own 
       case XSConstants.INTEGER_DT: 
       case XSConstants.DECIMAL_DT: 
       case XSConstants.INT_DT: 
       case XSConstants.LONG_DT: 
       case XSConstants.SHORT_DT: 
       case XSConstants.BYTE_DT: 
       case XSConstants.UNSIGNEDBYTE_DT: 
       case XSConstants.UNSIGNEDINT_DT: 
       case XSConstants.UNSIGNEDLONG_DT: 
       case XSConstants.UNSIGNEDSHORT_DT: 
        return new Integer(var.normalizedValue); 
       case XSConstants.DATE_DT: 
       case XSConstants.DATETIME_DT: 
       case XSConstants.GDAY_DT: 
       case XSConstants.GMONTH_DT: 
       case XSConstants.GMONTHDAY_DT: 
       case XSConstants.GYEAR_DT: 
       case XSConstants.GYEARMONTH_DT: 
       case XSConstants.DURATION_DT: 
       case XSConstants.TIME_DT: 
        return new Date(var.normalizedValue); 
       case XSConstants.FLOAT_DT: 
        return new Float(Float.parseFloat(var.normalizedValue)); 
       case XSConstants.DOUBLE_DT: 
        return new Double(Double.parseDouble(var.normalizedValue)); 
       case XSConstants.STRING_DT: 
       case XSConstants.QNAME_DT: 
        return var.normalizedValue; 
       default: 
        throw new RuntimeException("Unknown datatype " + var.actualValueType + " for variable " + variableName + " in namespace " + variableName.getNamespaceURI()); 
       } 
      } 
     } 
     throw new RuntimeException("Could not resolve value " + variableName + " in namespace " + variableName.getNamespaceURI()); 
    } 

    public void addFunction(String namespace, String name, XPathFunction function) { 
     Hashtable table; 
     if(!functions.containsKey(namespace)) { 
      table = new Hashtable(); 
      functions.put(namespace, table); 
     } else { 
      table = (Hashtable)functions.get(namespace); 
     } 
     table.put(name, function); 
    } 

} 

기능은 분명히 일반적으로 (사용자 정의 코드를 실행하기 때문에, 즉 요점은 당신이 당신의 O를 쓰기 때문이다, 위 내에 포함 할 수 없습니다 WN 클래스), 그래서는/어떻게 든 evaluateImpl (당신의 자신의 논리 ..)를 하위 클래스로 구현할 다음

public abstract class XPathFunctionImpl implements XPathFunction { 

    /** 
    * This function is called by the XPath expression as it implements the interface XPathFunction 
    */ 

    protected int numberArguments; 

    public Object evaluate(List args) throws XPathFunctionException { 
     if(args.size() == numberArguments) { 
      return evaluateImpl(args); 
     } 
     throw new RuntimeException("Illegal number of arguments for " + this); 
    } 

    public abstract Object evaluateImpl(List args) throws XPathFunctionException; 

} 

같은 것을 함께 가야합니다.

이렇게하면 문자열 추가가 꽤 매력적으로 보입니다. 참고 :이 코드는 몇 년 전의 것이므로이 모든 작업을 수행하는 더 좋은 방법이있을 수 있습니다.

관련 문제