Есть ли способ автоматически определять пространства имен, записанные в теге root, используя libxml2? - PullRequest
1 голос
/ 04 марта 2020

Я пытаюсь написать синтаксический анализатор XML, используя libxml2 (2.9.1 -> Я знаю, что он старый, но я не могу сейчас его обновить). Используемый мной тестовый файл XML является конфиденциальным, поэтому я не могу поделиться им с вами. Но внутри файла у меня есть следующая строка:

<?xml version="1.0"?>
<log4j:test xmlns:log4j="http://jakarta.apache.org/log4j/">

Моя проблема связана с пространством имен log4j. При использовании xmlParseFile я предполагал, что он будет обнаружен автоматически, но нет. Я должен явно вызвать функцию xmlXPathRegisterNs.

Итак, мой вопрос: есть ли способ автоматически зарегистрировать пространства имен, считанные из файла? В приведенном ниже коде я не хочу явно вызывать xmlXPathRegisterNs.

Спасибо за вашу помощь.

PS: Вот мой код бета-теста

int main() {                                                                                                                                                  
  std::string inputFilename = "myfile.xml";                                                                                                                    

  xmlDocPtr document = xmlParseFile(inputFilename.c_str());
  if (document == nullptr) {
    std::cerr << "Document not parsed successfully" << std::endl;
    return -1;                                                                                        
  }                                                                                                                                                         

  xmlXPathContextPtr context = xmlXPathNewContext(document);                                                                                                
  if (context == nullptr) {                                                                                                                                 
    std::cerr << "Error in xmlXPathNewContext" << std::endl;                                                                                              
    return -1;
  }                                                                                                                                                         

  if (xmlXPathRegisterNs(context,  BAD_CAST "log4j", BAD_CAST "http://jakarta.apache.org/log4j/") != 0) {                                                   
      std::cerr << "Unable to register namespace" << std::endl;
      return -1;                                                                                             
  }                                                                                                                                                         

  xmlChar *xpath = (xmlChar*) "//log4j:test/log4j:event";                                                                                                
  xmlXPathObjectPtr nodesList = xmlXPathEvalExpression(xpath, context);                                                                                     
  if (nodesList == nullptr) {                                                                                                                               
    std::cerr << "Error in xmlXPathEvalExpression" << std::endl;                                                                                         
    return -1;
  }                                                                                                                                                         

  if (xmlXPathNodeSetIsEmpty(nodesList->nodesetval)) {                                                                                                      
    std::cerr << "No result found for //log4j:test/log4j:event" << std::endl;
    return -1;                                                                                     
  } else {                                                                                                                                                  
    xmlNodeSetPtr nodeset = nodesList->nodesetval;                                                                                                        

    for (int i{0}; i < nodeset->nodeNr; i++) {                                                                                                            
      xmlChar *keyword = xmlNodeListGetString(document, nodeset->nodeTab[i]->xmlChildrenNode, 1);                                                       
      std::cout << "Keyword: " << nodeset->nodeTab[i]->name << std::endl;                                                                               

      xmlFree(keyword);                                                                                                                                 
    }                                                                                                                                                     

    xmlXPathFreeObject(nodesList);                                                                                                                        
  }                                                                                                                                                         

  xmlFreeDoc(document);                                                                                                                                     
  xmlCleanupParser();                                                                                                                                       

  return 0;                                                                                                                                                 
} 

1 Ответ

1 голос
/ 04 марта 2020

На самом деле вы не пытаетесь написать XML парсер. libxml2 - это анализатор XML. Вы пытаетесь написать приложение, использующее синтаксический анализатор XML.

Когда вы пишете выражения XPath, вы можете привязать любой префикс, который вам нравится, к пространствам имен искомых элементов. Вам не нужно знать, какой префикс используется в исходном документе.

Если вы не хотите регистрировать привязку пространства имен, то ваши выражения XPath не могут использовать префиксы пространства имен и (учитывая, что это XPath 1.0) вам придется использовать обход //*[local-name()='test']/*[local-name()='event']

...