177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin#!/usr/bin/python 277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# 477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# Copyright (C) 2012 The Android Open Source Project 577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# 677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# Licensed under the Apache License, Version 2.0 (the "License"); 777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# you may not use this file except in compliance with the License. 877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# You may obtain a copy of the License at 977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# 1077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# http://www.apache.org/licenses/LICENSE-2.0 1177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# 1277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# Unless required by applicable law or agreed to in writing, software 1377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# distributed under the License is distributed on an "AS IS" BASIS, 1477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# See the License for the specific language governing permissions and 1677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# limitations under the License. 1777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# 1877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 1977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin""" 2077b63ca0447545a4dac3ac062f218d878ce01ba0Igor MurashkinUsage: 2177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin metadata_validate.py <filename.xml> 2277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin - validates that the metadata properties defined in filename.xml are 2377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin semantically correct. 2477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin - does not do any XSD validation, use xmllint for that (in metadata-validate) 2577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 2677b63ca0447545a4dac3ac062f218d878ce01ba0Igor MurashkinModule: 2777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin A set of helpful functions for dealing with BeautifulSoup element trees. 2877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Especially the find_* and fully_qualified_name functions. 2977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 3077b63ca0447545a4dac3ac062f218d878ce01ba0Igor MurashkinDependencies: 3177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin BeautifulSoup - an HTML/XML parser available to download from 3277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin http://www.crummy.com/software/BeautifulSoup/ 3377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin""" 3477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 3577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkinfrom bs4 import BeautifulSoup 3696bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkinfrom bs4 import Tag 3777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkinimport sys 3877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 3977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 4077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin##################### 4177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin##################### 4277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 4377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkindef fully_qualified_name(entry): 4477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin """ 4577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Calculates the fully qualified name for an entry by walking the path 4677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin to the root node. 4777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 4877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Args: 4977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin entry: a BeautifulSoup Tag corresponding to an <entry ...> XML node 5077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 5177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Returns: 5277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin A string with the full name, e.g. "android.lens.info.availableApertureSizes" 5377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin """ 5477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin filter_tags = ['namespace', 'section'] 5577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin parents = [i['name'] for i in entry.parents if i.name in filter_tags] 5677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 5777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin name = entry['name'] 5877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 5977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin parents.reverse() 6077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin parents.append(name) 6177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 6277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin fqn = ".".join(parents) 6377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 6477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin return fqn 6577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 6677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkindef find_parent_by_name(element, names): 6777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin """ 6877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Find the ancestor for an element whose name matches one of those 6977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin in names. 7077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 7177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Args: 7277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin element: A BeautifulSoup Tag corresponding to an XML node 7377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 7477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Returns: 7577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin A BeautifulSoup element corresponding to the matched parent, or None. 7677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 7777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin For example, assuming the following XML structure: 7877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin <static> 7977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin <anything> 8077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin <entry name="Hello" /> # this is in variable 'Hello' 8177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin </anything> 8277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin </static> 8377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 8477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin el = find_parent_by_name(Hello, ['static']) 8577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin # el is now a value pointing to the '<static>' element 8677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin """ 8777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin matching_parents = [i.name for i in element.parents if i.name in names] 8877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 8977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin if matching_parents: 9077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin return matching_parents[0] 9177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin else: 9277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin return None 9377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 9496bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkindef find_all_child_tags(element, tag): 9596bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin """ 9696bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin Finds all the children that are a Tag (as opposed to a NavigableString), 9796bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin with a name of tag. This is useful to filter out the NavigableString out 9896bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin of the children. 9996bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin 10096bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin Args: 10196bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin element: A BeautifulSoup Tag corresponding to an XML node 10296bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin tag: A string representing the name of the tag 10396bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin 10496bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin Returns: 10596bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin A list of Tag instances 10696bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin 10796bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin For example, given the following XML structure: 10896bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin <enum> # This is the variable el 10996bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin Hello world # NavigableString 11096bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin <value>Apple</value> # this is the variale apple (Tag) 11196bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin <value>Orange</value> # this is the variable orange (Tag) 11296bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin Hello world again # NavigableString 11396bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin </enum> 11496bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin 11596bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin lst = find_all_child_tags(el, 'value') 11696bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin # lst is [apple, orange] 11796bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin 11896bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin """ 11996bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin matching_tags = [i for i in element.children if isinstance(i, Tag) and i.name == tag] 12096bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin return matching_tags 12196bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin 12296bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkindef find_child_tag(element, tag): 12396bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin """ 12496bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin Finds the first child that is a Tag with the matching name. 12596bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin 12696bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin Args: 12796bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin element: a BeautifulSoup Tag 12896bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin tag: A String representing the name of the tag 12996bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin 13096bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin Returns: 13196bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin An instance of a Tag, or None if there was no matches. 13296bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin 13396bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin For example, given the following XML structure: 13496bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin <enum> # This is the variable el 13596bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin Hello world # NavigableString 13696bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin <value>Apple</value> # this is the variale apple (Tag) 13796bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin <value>Orange</value> # this is the variable orange (Tag) 13896bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin Hello world again # NavigableString 13996bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin </enum> 14096bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin 14196bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin res = find_child_tag(el, 'value') 14296bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin # res is apple 14396bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin """ 14496bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin matching_tags = find_all_child_tags(element, tag) 14596bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin if matching_tags: 14696bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin return matching_tags[0] 14796bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin else: 14896bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin return None 14996bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin 15077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkindef find_kind(element): 15177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin """ 15277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Finds the kind Tag ancestor for an element. 15377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 15477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Args: 15577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin element: a BeautifulSoup Tag 15677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 15777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Returns: 15877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin a BeautifulSoup tag, or None if there was no matches 15977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 16077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Remarks: 16177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin This function only makes sense to be called for an Entry, Clone, or 16277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin InnerNamespace XML types. It will always return 'None' for other nodes. 16377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin """ 16477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin kinds = ['dynamic', 'static', 'controls'] 16577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin parent_kind = find_parent_by_name(element, kinds) 16677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin return parent_kind 16777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 16877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkindef validate_error(msg): 16977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin """ 17077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Print a validation error to stderr. 17177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 17277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Args: 17377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin msg: a string you want to be printed 17477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin """ 17577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin print >> sys.stderr, "Validation error: " + msg 17677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 17777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 17877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkindef validate_clones(soup): 17977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin """ 18077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Validate that all <clone> elements point to an existing <entry> element. 18177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 18277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Args: 18377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin soup - an instance of BeautifulSoup 18477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 18577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Returns: 18677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin True if the validation succeeds, False otherwise 18777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin """ 18877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin success = True 18977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 19077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin for clone in soup.find_all("clone"): 19177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin clone_entry = clone['entry'] 19277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin clone_kind = clone['kind'] 19377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 19477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin parent_kind = find_kind(clone) 19577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 19677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin find_entry = lambda x: x.name == 'entry' \ 19777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin and find_kind(x) == clone_kind \ 19877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin and fully_qualified_name(x) == clone_entry 19977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin matching_entry = soup.find(find_entry) 20077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 20177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin if matching_entry is None: 20277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin error_msg = ("Did not find corresponding clone entry '%s' " + \ 20377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin "with kind '%s'") %(clone_entry, clone_kind) 20477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin validate_error(error_msg) 20577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin success = False 20677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 20777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin return success 20877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 20977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# All <entry> elements with container=$foo have a <$foo> child 21096bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin# If type="enum", <enum> tag is present 21196bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin# In <enum> for all <value id="$x">, $x is numeric 21277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkindef validate_entries(soup): 21377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin """ 21477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Validate all <entry> elements with the following rules: 21577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin * If there is a container="$foo" attribute, there is a <$foo> child 21696bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin * If there is a type="enum" attribute, there is an <enum> child 21796bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin * In the <enum> child, all <value id="$x"> have a numeric $x 21877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 21977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Args: 22077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin soup - an instance of BeautifulSoup 22177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 22277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Returns: 22377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin True if the validation succeeds, False otherwise 22477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin """ 22577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin success = True 22677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin for entry in soup.find_all("entry"): 22777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin entry_container = entry.attrs.get('container') 22877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 22977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin if entry_container is not None: 23077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin container_tag = entry.find(entry_container) 23177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 23277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin if container_tag is None: 23377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin success = False 23477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin validate_error(("Entry '%s' in kind '%s' has type '%s' but " + \ 23577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin "missing child element <%s>") \ 23677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin %(fully_qualified_name(entry), find_kind(entry), \ 23777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin entry_container, entry_container)) 23877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 239b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin enum = entry.attrs.get('enum') 240b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin if enum and enum == 'true': 24196bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin if entry.enum is None: 24296bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin validate_error(("Entry '%s' in kind '%s' is missing enum") \ 24396bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin % (fully_qualified_name(entry), find_kind(entry), 24496bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin )) 245b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin success = False 24696bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin 247b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin else: 24896bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin for value in entry.enum.find_all('value'): 24996bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin value_id = value.attrs.get('id') 25096bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin 25196bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin if value_id is not None: 25296bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin try: 25396bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin id_int = int(value_id, 0) #autoguess base 25496bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin except ValueError: 25596bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin validate_error(("Entry '%s' has id '%s', which is not" + \ 25696bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin " numeric.") \ 25796bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin %(fully_qualified_name(entry), value_id)) 25896bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin success = False 259b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin else: 260b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin if entry.enum: 261b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin validate_error(("Entry '%s' kind '%s' has enum el, but no enum attr") \ 262b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin % (fully_qualified_name(entry), find_kind(entry), 263b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin )) 264b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin success = False 26596bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin 26696bd019289c47433e1b3522500bb166a4662e0f5Igor Murashkin return success 26777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 26877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkindef validate_xml(file_name): 26977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin """ 27077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Validate all XML nodes according to the rules in validate_clones and 27177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin validate_entries. 27277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 27377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Args: 27477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin file_name - a string path to an XML file we wish to validate 27577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 27677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin Returns: 27777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin a BeautifulSoup instance if validation succeeds, None otherwise 27877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin """ 27977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 28077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin xml = file(file_name).read() 28177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin soup = BeautifulSoup(xml, features='xml') 28277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 28377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin succ = validate_clones(soup) 28477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin succ = validate_entries(soup) and succ 28577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 28677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin if succ: 28777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin return soup 28877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin else: 28977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin return None 29077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 29177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin##################### 29277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin##################### 29377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 29477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkinif __name__ == "__main__": 29577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin if len(sys.argv) <= 1: 29677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin print >> sys.stderr, "Usage: %s <filename.xml>" % (sys.argv[0]) 29777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin sys.exit(0) 29877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 29977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin file_name = sys.argv[1] 30077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin succ = validate_xml(file_name) is not None 30177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin 30277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin if succ: 30377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin print "%s: SUCCESS! Document validated" %(file_name) 30477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin sys.exit(0) 30577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin else: 30677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin print >> sys.stderr, "%s: ERRORS: Document failed to validate" %(file_name) 30777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin sys.exit(1) 308