Это самый эффективный способ выразить этот запрос XDocument? - PullRequest
5 голосов
/ 12 января 2009

Мы используем сторонний веб-сервис, который возвращает XML, который выглядит примерно так (сокращенно для краткости):

<Response>
  <block name="availability">
    <block name="cqual">
      <a name="result-code" format="text">L</a>
    </block>
    <block name="exchange">
      <a name="code" format="text">MRDEN</a>
    </block>
    <block name="mqual">
      <a name="rate-adaptive" format="text">G</a>
    </block>
  </block>
  <block name="products">
    <block>
      <a name="product-id" format="counting">1235</a>
      <block name="realms">
        <block>
          <a name="realm" format="text">-u@surfuk1</a>
        </block>
      </block>
    </block>
    <block>
      <a name="product-id" format="counting">1236</a>
      <block name="realms">
        <block>
          <a name="realm" format="text">-u@surfuk2</a>
        </block>
      </block>
    </block>
    <block>
      <a name="product-id" format="counting">1237</a>
      <block name="realms">
        <block>
          <a name="realm" format="text">-u@surfuk3</a>
        </block>
      </block>
    </block>
  </block>
  <status no="0" />
</Response>

Для конкретного кода продукта мне нужно получить имя realm, т.е. внутренний текст:

<a name="realm" format="text"> -u @ surfuk2 </a>

Поскольку каждое имя элемента является либо <block>, либо <a>, его немного сложно проанализировать с помощью linq to xml или выражений запросов.

Является ли следующий наиболее эффективный / действенный / выразительный способ получить название области для определенного продукта, например, 1235

List<XElement> products = response
    .Element("Response")
    .Elements("block")
    .Where(x => x.Attribute("name").Value == "products")
    .Elements("block").ToList();
//
// I broke down the query to aid readability
//
string realm = products.Elements("a")
    .Where(x => x.Attribute("name").Value == "product-id")
    .Where(y => y.Value == "1235") // hardcoded for example use
    .Ancestors()
    .First()
    .Elements("block")
    .Where(z => z.Attribute("name").Value == "realms")
    .Elements("block")
    .Elements("a")
    .First().Value;

Ответы [ 2 ]

2 голосов
/ 12 января 2009

Определение realm, как указано, является эквивалентом более простого :

string realm = (string) products.XPathEvaluate(
   "string(
      /*/blocks[@name='products']
                 /*/a[@name='product-id' and . = '1236']
                              /following-sibling::block[1]
          )
   "
                                     )

Это на самом деле и более читабельно, и более компактно , чем определение realm, приведенное в исходном вопросе.

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

0 голосов
/ 12 января 2009

Вроде бы так, но зачем вам все звонки ToList()? Я вижу три из этих вызовов, и я не думаю, что они нужны, поэтому они просто замедляют ваш код. Но опять же, я не использовал много Linq-to-XMl.

...