web-dev-qa-db-de.com

So ignorieren Sie den Namespace bei der Auswahl von XML-Knoten mit XPath

Ich muss ein XML-Dokument analysieren, das so aussieht:

 <?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>

Das Problem ist, dass der Namespace "http://oasissta.caiso.com/mrtu-oasis/xsd/OASISReport.xsd" manchmal unterschiedlich sein kann. Ich möchte es komplett ignorieren und meine Daten einfach vom Tag MessagePayload Downstream beziehen.

Der Code, den ich bisher benutze, ist:

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());

Es funktioniert gut, wenn sich der Namespace nie ändert, aber das ist offensichtlich nicht der Fall. Was muss ich tun, damit der Namespace ignoriert wird? Oder wie kann ich alle möglichen Namespace-Werte an die XPath-Instanz übergeben, wenn ich sie kenne?

55
lukegf

Verwenden:

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

Möchte jemand eine umfassendere Syntax?

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

Übrigens, wenn der XPath auch die Elementindexposition benötigt:

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

Dies ist FAQ (aber ich bin faul, Duplikate heute zu suchen)

In XPath 1.0

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

Wählt jedes Element mit "name" als lokaler Name aus.

In XPath 2.0 können Sie Folgendes verwenden:

//*:name
117
user357812