Использование XQUERY для получения значения атрибутов - PullRequest
2 голосов
/ 10 января 2012

Можно ли использовать XQUERY для получения атрибутов filename из следующего XML?Я пытаюсь использовать /preFileDoc/inpXML/@filename, но это не работает ...

<?xml version="1.0"?>
<preFileDoc xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
  <senderId>ABC</senderId>
  <receiverId>XYZ</receiverId>
  <tranxCode>A001</tranxCode>
  <inpXML version="1.0" encoding="UTF-8">
    <soap-env:Envelope>
      <soap-env:Header msgcode="SPPCONVAKT" orig-system="002FTB" refid="65355ff50a172064484bf9da64c1e245" timestamp="2009-02-11 21:00:10.741" filename="SPPCONVAKT20090128001.dat"/>
      <soap-env:Body>
text1
text2
      </soap-env:Body>
    </soap-env:Envelope>
  </inpXML>
</preFileDoc>

пс: иногда атрибуты filename отправляются как fileName во входящем XML.. думая получить значение из атрибутов @filename ИЛИ @fileName .. это может быть достигнуто в одном XQUERY?Спасибо за совет ...

Ответы [ 3 ]

2 голосов
/ 10 января 2012

Я думаю, что ваш XPath не завершен.Последний дочерний шаг / в /preFileDoc/inpXML/@filename соответствует только атрибутам элемента inpXML, а не его потомкам.

Одним из способов решения проблемы может быть // -этап:

/preFileDoc/inpXML//@filename

Обратите внимание, что при этом все атрибуты с именем filename будут найдены и в soapenv:Body.

Таким образом, более надежный способ - объявить префикс soapenv в XQuery:

declare namespace soap-env="http://schemas.xmlsoap.org/soap/envelope/";

return /preFileDoc/inpXML//soap-env:Header/@filename

Наконец, различные заглавные буквы filename можно обойти, указав оба:

declare namespace soap-env="http://schemas.xmlsoap.org/soap/envelope/";

return /preFileDoc/inpXML//soap-env:Header/(@filename | @fileName)
1 голос
/ 10 января 2012

Вы можете взять объединение нескольких атрибутов. Маловероятно, что этот атрибут будет появляться несколько раз в разных регистрах, поэтому всегда следует возвращать один узел:

//soap-env:Header/@filename | //soap-env:Header/@fileName

При желании вы можете заключить его в скобки и добавить [1] за ним, чтобы всегда получать первый результат.

(//soap-env:Header/@filename | //soap-env:Header/@fileName)[1]

Если вы замените объединение запятой, которая создает последовательность вместо набора узлов порядка документов, вы также можете добавить значение по умолчанию в конце. Может быть, не очень полезно здесь, но, возможно, в других ситуациях:

(//soap-env:Header/@filename , //soap-env:Header/@fileName, "default.dat")[1]

НТН!

0 голосов
/ 10 января 2012

Вы должны уважать и учитывать пространство имен SOAP XML!

Поскольку я не знаю, что вы используете, я не могу рассказать вам, как это сделать - но на корневом узле есть xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/", а ваш атрибут @filename на узле <soap-env:Header .... /> - поэтому вам нужно включить пространство имен XML в ваш XQuery.

В .NET / C # вы можете сделать это следующим образом (используя «старый» стиль XmlDocument, который напрямую поддерживает XPath):

// define test XML 
string xmlContent = 
   @"<?xml version='1.0'?>
     <preFileDoc xmlns:soap-env='http://schemas.xmlsoap.org/soap/envelope/'>
        <senderId>ABC</senderId>
        <receiverId>XYZ</receiverId>
        <tranxCode>A001</tranxCode>
        <inpXML version='1.0' encoding='UTF-8'>
           <soap-env:Envelope>
              <soap-env:Header msgcode='SPPCONVAKT' orig-system='002FTB' refid='65355ff50a172064484bf9da64c1e245' timestamp='2009-02-11 21:00:10.741' filename='SPPCONVAKT20090128001.dat'/>
              <soap-env:Body>
                text1
                text2
              </soap-env:Body>
           </soap-env:Envelope>
        </inpXML>
     </preFileDoc>";

// create XmlDocument and load test data
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlContent);

// define XML namespace manager and add the SOAP namespace to it
XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable);
mgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");

// use XPath and the XML namespaces to grab the <Header> node
// the first two nodes <preFileDoc> and <inpXML> are not inside any explicit
// XML namespace
// but the next two (<Envelope> and <Header>) are in the "soap" XML namespace
XmlNode header = doc.SelectSingleNode("/preFileDoc/inpXML/soap:Envelope/soap:Header", mgr);

// read the "filename" attribute from the header node
if(header != null && header.Attributes["filename"] != null)
{
    string fileName = header.Attributes["filename"].Value;
}
...