使用XQUERY检索属性值

时间:2012-01-10 08:37:30

标签: xquery

是否可以使用XQUERY从以下XML中检索属性filename?我正在尝试使用 /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>

ps:有时filename属性在传入的XML中发送为fileName。思考从属性@filename@fileName中检索值..它可以实现单XQUERY?谢谢你的建议...

3 个答案:

答案 0 :(得分:2)

我认为您的XPath不完整。 /中的最后一个子步骤/preFileDoc/inpXML/@filename仅匹配inpXML元素的属性,而不匹配其后代。

解决问题的一种方法是// - 步骤:

/preFileDoc/inpXML//@filename

请注意,这也会在filename中找到名为soapenv:Body的所有属性。

因此,更健壮的方法是在XQuery中声明soapenv前缀:

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 :(得分:1)

您可以使用多个属性的并集。此属性不太可能出现多次使用不同的大小写,因此应始终返回单个节点:

//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]

HTH!

答案 2 :(得分:0)

您需要尊重并考虑SOAP XML名称空间!

由于我不知道您在使用什么,我无法告诉您如何执行此操作 - 但根节点上有xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"@filename属性位于<soap-env:Header .... /> 1}} node - 所以你需要在XQuery中包含XML命名空间。

在.NET / C#中,您可以这样做(使用直接支持XPath的“旧版”XmlDocument样式):

// 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;
}