How to ignore namespace when selecting XML nodes with XPath

好久不见. 提交于 2019-11-26 09:35:19

问题


I have to parse an XML document that looks like this:

 <?xml version=\"1.0\" encoding=\"UTF-8\" ?> 
 <m:OASISReport xmlns:m=\"http://oasissta.caiso.com/mrtu-oasis/xsd/OASISReport.xsd\" 
                xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
                xsi:schemaLocation=\"http://oasissta.caiso.com/mrtu-oasis/xsd/OASISReport.xsd http://oasissta.caiso.com/mrtu-oasis/xsd/OASISReport.xsd\">
  <m:MessagePayload>
   <m:RTO>
    <m:name>CAISO</m:name> 
    <m:REPORT_ITEM>
     <m:REPORT_HEADER>
      <m:SYSTEM>OASIS</m:SYSTEM> 
      <m:TZ>PPT</m:TZ> 
      <m:REPORT>AS_RESULTS</m:REPORT> 
      <m:MKT_TYPE>HASP</m:MKT_TYPE> 
      <m:UOM>MW</m:UOM> 
      <m:INTERVAL>ENDING</m:INTERVAL> 
      <m:SEC_PER_INTERVAL>3600</m:SEC_PER_INTERVAL> 
     </m:REPORT_HEADER>
     <m:REPORT_DATA>
      <m:DATA_ITEM>NS_PROC_MW</m:DATA_ITEM> 
      <m:RESOURCE_NAME>AS_SP26_EXP</m:RESOURCE_NAME> 
      <m:OPR_DATE>2010-11-17</m:OPR_DATE> 
      <m:INTERVAL_NUM>1</m:INTERVAL_NUM> 
      <m:VALUE>0</m:VALUE> 
     </m:REPORT_DATA>

The problem is that the namespace \"http://oasissta.caiso.com/mrtu-oasis/xsd/OASISReport.xsd\" can sometimes be different. I want to ignore it completely and just get my data from tag MessagePayload downstream.

The code I am using so far is:

String[] namespaces = new String[1];
  String[] namespaceAliases = new String[1];

  namespaceAliases[0] = \"ns0\";
  namespaces[0] = \"http://oasissta.caiso.com/mrtu-oasis/xsd/OASISReport.xsd\";

  File inputFile = new File(inputFileName);

  Map namespaceURIs = new HashMap();

  // This query will return all of the ASR records.
  String xPathExpression = \"/ns0:OASISReport
                             /ns0:MessagePayload
                              /ns0:RTO
                               /ns0:REPORT_ITEM
                                /ns0:REPORT_DATA\";
  xPathExpression += \"|/ns0:OASISReport
                        /ns0:MessagePayload
                         /ns0:RTO
                          /ns0:REPORT_ITEM
                           /ns0:REPORT_HEADER\";

  // Load up the raw XML file. The parameters ignore whitespace and other
  // nonsense,
  // reduces DOM tree size.
  SAXReader reader = new SAXReader();
  reader.setStripWhitespaceText(true);
  reader.setMergeAdjacentText(true);
  Document inputDocument = reader.read(inputFile);

  // Relate the aliases with the namespaces
  if (namespaceAliases != null && namespaces != null)
  {
   for (int i = 0; i < namespaceAliases.length; i++)
   {
    namespaceURIs.put(namespaceAliases[i], namespaces[i]);
   }
  }

  // Cache the expression using the supplied namespaces.
  XPath xPath = DocumentHelper.createXPath(xPathExpression);
  xPath.setNamespaceURIs(namespaceURIs);

  List asResultsNodes = xPath.selectNodes(inputDocument.getRootElement());

It works fine if the namespace never changes but that is obviously not the case. What do I need to do to make it ignore the namespace? Or if I know the set of all possible namespace values, how can I pass them all to the XPath instance?


回答1:


Use:

/*/*/*/*/*
        [local-name()='REPORT_DATA' 
       or 
         local-name()='REPORT_HEADER'
        ]

Anyone care for more complete syntax?

String xPathExpression = "/*[local-name()='OASISReport]
                          /*[local-name()='MessagePayload]
                          /*[local-name()='RTO]
                          /*[local-name()='REPORT_ITEM]
                          /*[local-name()='REPORT_DATA"];

Btw, if the XPath also requires the element index position:

String xPathExpression = "/*[local-name()='OASISReport][1]



回答2:


This is FAQ (but I'm lazy to search duplicates today)

In XPath 1.0

//*[local-name()='name']

Selects any element with "name" as local-name.

In XPath 2.0 you can use:

//*:name


来源:https://stackoverflow.com/questions/4402310/how-to-ignore-namespace-when-selecting-xml-nodes-with-xpath

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!