ColdFusion: мне нужно использовать structKeyExists для каждого элемента глубокой структуры? - PullRequest
2 голосов
/ 16 февраля 2011

Допустим, я только что проанализировал чужой XML-документ, который является ответом на запрос API.Я хочу знать, существует ли значение, вложенное глубоко внутрь.Если мой запрос API сработал, он будет каждый раз в одном и том же месте.Если мой запрос API терпит неудачу, корень XML очень отличается.

Если я попытаюсь <cfif structKeyExists(myStruct.level1.level2.level3, 'myTarget')> при неудачном запросе API, я получу фатальную ошибку: Element LEVEL1.LEVEL2 is undefined in MYSTRUCT.

OfКонечно, я мог бы попытаться зависеть от корневого уровня XML, говорящего мне об успехе или неудаче, и не искать результат, если он потерпел неудачу, но ... за исключением этого решения, что мне делать?

Нужно ли проверять наличие каждого уровня структуры?Как в:

<cfif structKeyExists(myStruct, 'level1') 
  and structKeyExists(myStruct.level1, 'level2') 
    and structKeyExists(myStruct.level1.level2, 'level3') 
      and structKeyExists(myStruct.level1.level2.level3, 'myTarget')>
<!--- ... --->
</cfif>

Это не проблема реального мира, это просто то, с чем я сталкивался слишком много раз.Пожалуйста, не говорите мне о решениях, которые включают изменение API или решений, подобных тем, что описаны в третьем абзаце.

Спасибо!

edit: я должен был упомянуть, почему я не могу использовать isDefined ()- некоторые ключи не имеют синтаксически допустимых имен, поэтому isDefined () выдает ошибку, например myStruct.level1 [42] .level3

Ответы [ 5 ]

5 голосов
/ 16 февраля 2011

XMLSearch

Я бы использовал проанализированный XML-документ (т.е. xmlDoc) и XMLSearch :

<cfset xmlDoc = xmlParse(responseData)>
<cfset nodes = XmlSearch(xmlDoc, '/level1/level2/level3/myTarget')>
<cfif arrayLen(nodes)>
    <!--- do something, you have the "nodes" array to work with too --->
</cfif>

xpath для XMLSearch() предполагает, что структурные ключи являются узлами. Вам нужно будет соответственно изменить, если, например, «myTarget» является атрибутом узла.

StructFindKey

Еще один способ сделать это - StructFindKey .

<cfset result = structFindKey(myStruct, "myTarget")>
<cfif arrayLen(result) AND result.path EQ "level1.level2.level3">
    <!--- do something --->
</cfif>

Заключение

Не тестировал, но я думаю, что будет быстрее, чем при использовании IsDefined() или блока try-catch. Имеет преимущество перед XMLValidate() в том, что не нуждается в DTD. И даже с DTD нужный вам узел может быть определен как необязательный, поэтому он все еще может проверяться.

3 голосов
/ 16 февраля 2011

Вы можете проверить XML по DTD, чтобы убедиться, что документ был в правильном формате. XmlParse() и XmlValidate() оба принимают DTD в качестве параметра.

<cfset validateResult = XmlValidate(myXmlDocument, myDTD)>
<cfif validateResult.status>
    <!--- xml is valid continue processing --->
<cfelse>
    <!--- xml did not validate handle the error --->
</cfif>
2 голосов
/ 17 февраля 2011

Я знаю, что меня здесь освистят, но именно здесь isDefined() может сэкономить вам много времени:

<cfif isDefined(structKeyExists(myStruct.level1.level2.level3)>
<!--- do something --->
</cfif>
2 голосов
/ 16 февраля 2011

Лично я бы не сходил с ума, проверяя каждый уровень «глубокой» структуры, подобной этой.Я бы предположил, что если существует верхний уровень, остальная часть документа будет такой, как вы ожидаете, и я бы просто обратился к документу оттуда.

Если вы хотите, вы можете попытаться обратиться к значению в вашей структуре и обернуть его в try/catch.Таким образом, вы можете обрабатывать любые ошибки на любом «уровне» таким же образом.

<cftry>

  <cfset myVar = myStruct.level1.level2.level3 />

<cfcatch type="any">
  <!--- Handle error --->
</cfcatch>
</cftry>

Надеюсь, это поможет некоторым.

1 голос
/ 15 февраля 2012

Я знаю, что это год, но я собираюсь вставить ответ здесь. Я долго боролся с этим, пока не нашел простое решение. Если я уже знаю структуру XML, простой IsDefined работает, чтобы проверить, существует ли узел или атрибут узла. Я не думаю, что большинство людей знают, что вы можете сделать это, или пытались, и потерпели неудачу, потому что они не включали одинарные кавычки в функцию IsDefined.

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

<cfhttp url="https://mycompany.com/mywebservices/getusers" username="me" password="mysecret">
<cfset userXMLDoc = XMLParse(ToString(cfhttp.FileContent).trim())>

<cfif IsDefined('userXMLDoc.Data.Record.User.XmlAttributes.id')>
  <cfdump var="#userXMLDoc.Data.Record.User.XmlAttributes.id#">
<cfelse>
  <cfoutput>Failed: No User ID found</cfoutput>
</cfif>
...