HTML 解析指南

使用下面列出的组、属性和其他 XML 属性解析 VuSitu 或 HydroVu HTML 文件。 使用本页底部用 Python 编写的示例解析器作为您自己的脚本的模型,或自定义代码以满足您的需求。 我们还提供了几个您可以用于测试的 VuSitu HTML 文件

组别

位置属性
报告属性 
仪器属性 
记录属性 
测试属性 
井属性 
泵属性 
管道属性 

位置属性

名称
全局唯一标识符 
纬度 
经度 

报告属性

起始时间
创建者 
时长 
读数 
时间偏差 

仪器属性

型号 
序列号 
固件版本 

记录属性

记录类型
名称
全局唯一标识符 
文件编号 
记录包装 

记录线性属性

间隔

记录对数属性

间隔

记录线性平均属性

间隔 
平均间隔 
样本大小 

记录步骤属性

间隔
计数 
时长 

记录事件属性

采样间隔 
默认间隔 
高阈值 
低阈值 
更改阈值 
自上次记录阈值以来的变化

低流量测试属性

测试类型 
起始时间 
时间偏差 
项目名称 
操作员姓名 
流通池体积 
到水的初始深度 
最终水位下降 
总系统体积 
总泵送量

井属性

套管类型 
直径 
长度 
总深度 
到屏幕的深度 
屏幕长度

泵属性

模型 
流速 
体积 
从外壳顶部送进 
最终抽水率 

管道属性

管道类型 
直径 
长度

XML 属性:

  • isi-group: 

定义 isi-group-members 使用的标识符,以有逻辑地组合在一起。

示例:isi-group="LocationProperties"

  • isi-group-member:

将项目标识为组成员。

示例:isi-group-member="地点属性"

  • isi-property:

将项目标识为"属性",格式为<Key> <Value>

<tr isi-property="Name"><td>Name = My Location</td></tr>

  • isi-label:

将元素标识为本地化标签,以与值侧隔离

示例:<tr><td><span isi-label="">Name</span> = My Location</td></tr>

  • isi-value:

指示解析器当前元素包含一个值 示例:

<tr><td>Name = <span isi-value="">My Location</span></td></tr>

  • isi-text-node:

指示解析器该值不作为当前元素的属性存在 示例:

<tr><td isi-text-node="">Name = My Location</td></tr>

  • isi-datetime:

提供 ISO 标准日期时间格式的字符串 示例:

<tr><td isi-datetime="2017-10-08T13:05:30-06:00">Start Time = 10/08/2017 1:05 PM</td> </tr>

  • isi-timespan-milliseconds:

提供整数毫秒持续时间 示例:

<tr><td isi-timespan-milliseconds="3600000">Duration = 01:00:00</td></tr>

  • isi-enabled:
  • 以字符串形式提供布尔值 示例:

<tr><td isi-enabled="True">Log Wrapping Enabled = True</td></tr>

  • isi-device-type:
  • 提供一个表示设备型号(系统规范设备类型)的整数值 示例:

<tr><td isi-device-type="7">Model = Aqua TROLL 600</td></tr>

  • isi-log-type:
  • 提供一个表示类型的整数值
  • isi-data-column-header:
  • 表示当前元素是数据列标题 示例:

<tr><td isi-data-column-header="">Temperature (F)</td></tr>

  • isi-device-serial-number:
  • 提供设备序列号 示例:

<tr><td isi-device-serial-number="1234">Temperature (F)</td></tr>

  • isi-sensor-serial-number:
  • 提供传感器序列号 示例:

<tr><td isi-sensor-serial-number="4567">Temperature (F)</td></tr>

  • isi-device-sensor-type:
  • 提供传感器类型(系统规格传感器类型) 示例:

<tr><td isi-sensor-type="1">Temperature (F)</td></tr>

  • isi-external-parameter:
  • 表示传感器来自外部来源(不是仪器的一部分) 示例:

<tr><td isi-external-parameter="">Temperature (F)</td></tr>

  • isi-parameter-type:
  • 提供传感器参数类型(系统规格参数类型) 示例:

<tr><td isi-parameter-type="1">Temperature (F)</td></tr>

  • isi-unit-type:
  • 提供传感器单元类型(系统规格单元类型) 示例:

<tr><td isi-unit-type="2">Temperature (F)</td></tr>

  • isi-data-table:
  • 表示时间序列数据表的开始 示例:

<tr isi-data-table=""><td>Temperature (F)</td></tr>

  • isi-data-row:
  • 表示时序数据表的数据行 示例:

<tr isi-data-row=""><td>98.6</td><td>32.0</td><td>100.0</td></tr>

  • isi-timestamp:
  •  提供整数形式的系统规范时间(内部定义) 示例:

<tr isi-timestamp="238900"><td>07/16/1969 20:18:00</td><td>100.0</td></tr>

  • isi-data-quality:
  • 表示时序数据表的数据具有非正常质量值(系统规数据质量类型) 示例:

<tr><td>98.6</td><td>32.0</td><td>100.0</td><td isi-data-quality="3">0</td></tr>

  • isi-marked:
  • 表示时间序列数据表的数据被标记(整行) 示例:

<tr isi-marked=""><td>98.6</td><td>32.0</td><td>100.0</td></tr>

  • isi-log-note:
  • 表示当前元素是记录注释的一部分 示例:

<tr><td isi-log-note="">10/08/2012 15:30:00 Sensor Changed</td></tr>

  • isi-log-note-type:
  • 以整数形式提供记录注释类型(系统规格日志注释类型) 示例:

<tr><td isi-log-note-type="12">10/08/2012 15:30:00 Sensor Changed</td></tr>

  • isi-lowflow-sample:
  • 表示当前元素是低流量样本的一部分 示例:

<tr><td isi-lowflow-sample=""><span isi-label="">Sample #931</span>: <span isi-value="">Pre test sample</span></td></tr>

  • isi-lowflow-note:
 表示当前元素包含一个低流量注释 示例:

<tr><td isi-lowflow-note=""><span>Weather Conditions</span>: <span>38.5 F, 78% humidity</span></td></tr>

解析文件注意事项

  • 要解析的数据从以下标签开始:<table id="isi-report">
  • 数据按表格行<tr>和该行中的<td>元素组织:
  • 请勿基于类别属性进行解析。 类别属性仅用于 Excel 内部的格式化,应视为可选
  • 根据上面列出的 XML 属性进行解析(例如:isi-group)。

 

解析器示例 (Python 2x)


从 HTMLParser 导入 HTMLParser

# 制作一个自定义版本的 HTML 解析器,通过覆盖来处理数据元素
class MyHTMLParser(HTMLParser):
    def FeedLine(self, line, reset):
        if reset:
            self.startStack = [];
            self.endStack = []
            self.elements = []
        self.feed(line)

    def handle_starttag(self, tag, attrs):
        self.startStack.append(tag)
        self.elements.append({})
        if len(attrs) > 0:
            self.elements[-1]["attrs"] = attrs

    def handle_endtag(self, tag):
        self.endStack.append(tag)

    def handle_data(self, data):
        if data.strip() == "" or data.strip().rstrip() == "=":
             return
        if len(self.elements) < 1:
            return

        self.elements[-1]["data"] = data

# 从属性列表中获取所提供类型的属性
def GetAttr(attrs, ofType):
    for attr in attrs:
        if attr[0] == ofType:
            return attr
    return None

# 判断属性列表是否包含提供的类型
def ContainsAttr(attrs, ofType):
    return GetAttr(attrs, ofType) is not None

# 扫描元素列表中的所有元素,查找所提供类型的属性
def GetAttrFromElements(elements, ofType):
    for element in elements:
        if 'attrs' not in element:
            continue
        for attr in element['attrs']:
            if attr[0] == ofType:
                return attr
    return None

def GetClass(elements):
    attr = GetAttrFromElements(elements, 'class')
    if attr is None:
        return None
    else:
        return attr[1]

parser = MyHTMLParser()

# 数据结构以保存文件数据
metadataGroups = {}
dataTables = []

# 打开 in-situ 数据文件
fptr = open('YOUR FILENAME HERE', 'r')

# 跳过显示 html 直接到我们感兴趣的数据
for line in fptr:
    parser.FeedLine(line, True)
    if 'body' in parser.startStack:
        break

# 逐行读取文件以节省内存
resetLine = True
for line in fptr:
    parser.FeedLine(line, resetLine)
    resetLine = True

    # 只对表格行感兴趣,如果不是 tr 则转到下一行
    if "tr" not in parser.startStack:
        continue

    # 确保我们加载了整个表格行,而不仅仅是一行
    if "tr" not in parser.endStack:
        resetLine = False
        continue

    # 跳过空行
    if len(parser.elements) < 1 or 'attrs' not in parser.elements[0]:
        continue

    startIndex = parser.startStack.index('tr')
    rootAttr = parser.elements[startIndex]['attrs']

    for element in parser.elements[startIndex:]:
        # 如果元素没有属性我们可以忽略它
        if 'attrs' not in element:
            continue

        if ContainsAttr(element['attrs'], 'isi-group'):
            attr = GetAttr(element['attrs'], 'isi-group')
            metadataGroups[attr[1]] = {}
            metadataGroups[attr[1]]["Name"] = attr[1]
        elif ContainsAttr(element['attrs'], 'isi-group-member'):
            attr = GetAttr(element['attrs'], 'isi-group-member')
            metaData = parser.elements[1]['attrs']
            groupName = GetAttr(metaData, 'isi-group-member')[1]

            isiProperty = GetAttr(element['attrs'], 'isi-property')
            if isiProperty is not None:
                label = parser.elements[2]['data']
                value = parser.elements[3]['data']
                metadataGroups[groupName][isiProperty[1]] = {'Label': label, 'Value': value}

            logNotes = GetAttr(element['attrs'], 'isi-log-note')
            if logNotes is not None:
                if "Notes" not in parser.elements[1]['attrs']:
                    metadataGroups[groupName]["Notes"] = []
                for attr in parser.elements[1]['attrs']:
                    metadataGroups[groupName]["Notes"].append({attr[0]:attr[1]})

        elif ContainsAttr(element['attrs'], 'isi-data-table'):
            dataTables.append({'Headers': [], 'Values': []})
        elif ContainsAttr(element['attrs'], 'isi-data-column-header'):
            hold = {'Name': element['data']}
            for attr in element:
                hold[attr[0]] = attr[1]
            dataTables[-1]['Headers'].append(hold)
        elif ContainsAttr(element['attrs'], 'isi-data-row'):
            hold = []
            # 此行中的所有元素都是数据,因此将它们全部处理然后中断
            for element in parser.elements:
                if 'attrs' in element and ContainsAttr(element['attrs'], 'isi-data-row'): # no data in the row setup
                    continue
                elif 'data' in element:
                    hold.append(element['data'])
                else:
                    hold.append(' ')
            dataTables[-1]['Values'].append(hold)

# 正为文件打印出元数据。
for key in metadataGroups.iterkeys():
    print (key)
    print ("\t", metadataGroups[key])
print ("\n")

# 打印数据
for table in dataTables:
    # 正在打印所有数据的标题行 - 注意:这里没有打印传感器类型等元数据
    for header in table['Headers']:
        print (header['Name'] + "\t",)
    print ("")
    # 正在打印数据行 - 与标题相同的顺序,使您可以正确将它们串联
    for row in table['Values']:
        
        for datum in row:
            print ("|" + datum + "|",)
        print ("")

解析器示例 (Python 3x)


从 html.parser 导入 HTMLParser

# 制作一个自定义版本的 HTML 解析器,通过覆盖来处理数据元素
class MyHTMLParser(HTMLParser):
    def FeedLine(self, line, reset):
        if reset:
            self.startStack = []
            self.endStack = []
            self.elements = []
        self.feed(line)

    def handle_starttag(self, tag, attrs):
        self.startStack.append(tag)
        self.elements.append({})
        if len(attrs) > 0:
            self.elements[-1]["attrs"] = attrs

    def handle_endtag(self, tag):
        self.endStack.append(tag)

    def handle_data(self, data):
        if data.strip() == "" or data.strip().rstrip() == "=":
             return
        if len(self.elements) < 1:
            return

        self.elements[-1]["data"] = data

# 从属性列表中获取所提供类型的属性
def GetAttr(attrs, ofType):
    for attr in attrs:
        if attr[0] == ofType:
            return attr
    return None

# 判断属性列表是否包含提供的类型
def ContainsAttr(attrs, ofType):
    return GetAttr(attrs, ofType) is not None

# 扫描元素列表中的所有元素,查找所提供类型的属性
def GetAttrFromElements(elements, ofType):
    for element in elements:
        if 'attrs' not in element:
            continue
        for attr in element['attrs']:
            if attr[0] == ofType:
                return attr
    return None

def GetClass(elements):
    attr = GetAttrFromElements(elements, 'class')
    if attr is None:
        return None
    else:
        return attr[1]

parser = MyHTMLParser()

# 数据结构以保存文件数据
metadataGroups = {}
dataTables = []

# 打开 in-situ 数据文件
fptr = open('YOUR FILENAME HERE', 'r')

# 跳过显示 html 直接到我们感兴趣的数据
for line in fptr:
    parser.FeedLine(line, True)
    if 'body' in parser.startStack:
        break

# 逐行读取文件以节省内存
resetLine = True
for line in fptr:
    parser.FeedLine(line, resetLine)
    resetLine = True

    # 只对表格行感兴趣,如果不是 tr 则转到下一行
    if "tr" not in parser.startStack:
        continue

    # 确保我们加载了整个表格行,而不仅仅是一行
    if "tr" not in parser.endStack:
        resetLine = False
        continue

    # 跳过空行
    if len(parser.elements) < 1 or 'attrs' not in parser.elements[0]:
        continue

    startIndex = parser.startStack.index('tr')
    rootAttr = parser.elements[startIndex]['attrs']

    for element in parser.elements[startIndex:]:
        # 如果元素没有属性我们可以忽略它
        if 'attrs' not in element:
            continue

        if ContainsAttr(element['attrs'], 'isi-group'):
            attr = GetAttr(element['attrs'], 'isi-group')
            metadataGroups[attr[1]] = {}
            metadataGroups[attr[1]]["Name"] = attr[1]
        elif ContainsAttr(element['attrs'], 'isi-group-member'):
            attr = GetAttr(element['attrs'], 'isi-group-member')
            metaData = parser.elements[1]['attrs']
            groupName = GetAttr(metaData, 'isi-group-member')[1]

            isiProperty = GetAttr(element['attrs'], 'isi-property')
            if isiProperty is not None:
                label = parser.elements[2]['data']
                value = parser.elements[3]['data']
                metadataGroups[groupName][isiProperty[1]] = {'Label': label, 'Value': value}

            logNotes = GetAttr(element['attrs'], 'isi-log-note')
            if logNotes is not None:
                if "Notes" not in parser.elements[1]['attrs']:
                    metadataGroups[groupName]["Notes"] = []
                for attr in parser.elements[1]['attrs']:
                    metadataGroups[groupName]["Notes"].append({attr[0]:attr[1]})

        elif ContainsAttr(element['attrs'], 'isi-data-table'):
            dataTables.append({'Headers': [], 'Values': []})
        elif ContainsAttr(element['attrs'], 'isi-data-column-header'):
            hold = {'Name': element['data']}
            for attr in element:
                hold[attr[0]] = attr[1]
            dataTables[-1]['Headers'].append(hold)
        elif ContainsAttr(element['attrs'], 'isi-data-row'):
            hold = []
            # 此行中的所有元素都是数据,因此将它们全部处理然后中断
            for element in parser.elements:
                if 'attrs' in element and ContainsAttr(element['attrs'], 'isi-data-row'): # no data in the row setup
                    continue
                elif 'data' in element:
                    hold.append(element['data'])
                else:
                    hold.append(' ')
            dataTables[-1]['Values'].append(hold)

# 正为文件打印出元数据。
for key in metadataGroups.keys():
    print (key)
    print ("\t", metadataGroups[key])

print ("\n")

# 打印数据
for table in dataTables:
    # 正在打印所有数据的标题行 - 注意:这里没有打印传感器类型等元数据
    for header in table['Headers']:
        print (header['Name'] + "\t",)
    print ("")
    # 正在打印数据行 - 与标题相同的顺序,使您可以正确将它们串联
    for row in table['Values']:
        for datum in row:
            print ("|" + datum + "|",)
        print ("")

h2 id="sampleFiles">VuSitu HTML 文件示例

记录样本 1

记录样本 2

记录样本 3

记录样本 4

记录样本 5

Headquarters: 221 E. Lincoln Ave, Fort Collins, CO, 80524, USA