sax 解析器获取空标记的 nex 值
sax parser getting nex value for empty tag
我正在尝试使用 sax 解析器获取 xm 的值,当标记为空时,像解析器一样而不是跳过该标记保存下一个标记的值,这里是我的解析器:
public class HandlerRegistrarActa extends DefaultHandler {
private RegistrarActaBeanReq acta = null;
private List<Infracciones> infracciones = null;
private Infracciones infraccion= null;
public RegistrarActaBeanReq getActa() {
return acta;
}
boolean bid_Acta = false;
boolean bNro_Acta = false;
boolean bLetra_Serie = false;
boolean bInfraccion_Lugar = false;
boolean bInfraccion_Numero = false;
boolean bInfraccion_KmAltura = false;
boolean bInfraccion_Referencia = false;
boolean bInfraccion_Fec_Hora_Labrada = false;
boolean bFec_Vencimiento = false;
boolean bRetiene_Licencia = false;
boolean bRetene_Vehiculo = false;
boolean bTipoVehiculo = false;
boolean bTipoPatente = false;
boolean bConduccionPeligrosa = false;
boolean bDominio = false;
boolean bMarca = false;
boolean bColor = false;
boolean bSinTitular = false;
boolean bTipo_Dni_Propietario = false;
boolean bDni_propietario = false;
boolean bNombre_Propietario = false;
boolean bApellido_Propietario = false;
boolean bRazon_Social_Propietario = false;
boolean bCalle_propietario = false;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if (qName.equalsIgnoreCase("id_Acta")) {
bid_Acta = true;
acta = new RegistrarActaBeanReq();
} else if (qName.equalsIgnoreCase("Nro_Acta")) {
bNro_Acta = true;
} else if (qName.equalsIgnoreCase("Letra_Serie")) {
bLetra_Serie = true;
} else if (qName.equalsIgnoreCase("Infraccion_Lugar")) {
bInfraccion_Lugar = true;
} else if (qName.equalsIgnoreCase("Infraccion_Numero_Ruta")) {
bInfraccion_Numero = true;
} else if (qName.equalsIgnoreCase("Infraccion_KmAltura")) {
bInfraccion_KmAltura = true;
} else if (qName.equalsIgnoreCase("Infraccion_Referencia")) {
bInfraccion_Referencia = true;
} else if (qName.equalsIgnoreCase("Fec_Hora_Labrada")) {
bInfraccion_Fec_Hora_Labrada = true;
} else if (qName.equalsIgnoreCase("Fec_Vencimiento")) {
bFec_Vencimiento = true;
} else if (qName.equalsIgnoreCase("Retiene_Licencia")) {
bRetiene_Licencia = true;
} else if (qName.equalsIgnoreCase("Retiene_Vehiculo")) {
bRetene_Vehiculo = true;
} else if (qName.equalsIgnoreCase("TipoVehiculo")) {
bTipoVehiculo = true;
} else if (qName.equalsIgnoreCase("TipoPatente")) {
bTipoPatente = true;
} else if (qName.equalsIgnoreCase("ConduccionPeligrosa")) {
bConduccionPeligrosa = true;
} else if (qName.equalsIgnoreCase("Dominio")) {
bDominio= true;
} else if (qName.equalsIgnoreCase("Marca")) {
bMarca = true;
} else if (qName.equalsIgnoreCase("Color")) {
bColor = true;
} else if (qName.equalsIgnoreCase("SinTitular")) {
bSinTitular = true;
} else if (qName.equalsIgnoreCase("Tipo_Dni_Propietario")) {
bTipo_Dni_Propietario = true;
} else if (qName.equalsIgnoreCase("Dni_propietario")) {
bDni_propietario = true;
} else if (qName.equalsIgnoreCase("Nombre_Propietario")) {
bNombre_Propietario = true;
} else if (qName.equalsIgnoreCase("Apellido_Propietario")) {
bApellido_Propietario = true;
} else if (qName.equalsIgnoreCase("Razon_Social_Propietario")) {
bRazon_Social_Propietario = true;
} else if (qName.equalsIgnoreCase("Calle_propietario")) {
bCalle_propietario = true;
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
}
@Override
public void characters(char ch[], int start, int length) throws SAXException {
if (bid_Acta) {
acta.setId_Acta(new String(ch, start, length).trim());
bid_Acta = false;
} else if (bNro_Acta) {
acta.setNro_Acta(new String(ch, start, length).trim());
bNro_Acta = false;
} else if (bLetra_Serie) {
acta.setLetra_Serie(new String(ch, start, length).trim());
bLetra_Serie = false;
} else if (bInfraccion_Lugar) {
acta.setInfraccion_Lugar(new String(ch, start, length).trim());
bInfraccion_Lugar = false;
} else if (bInfraccion_Numero) {
acta.setInfraccion_Numero_Ruta(new String(ch, start, length).trim());
bInfraccion_Numero = false;
} else if (bInfraccion_KmAltura) {
acta.setInfraccion_KmAltura(new String(ch, start, length).trim());
bInfraccion_KmAltura = false;
}else if (bInfraccion_Referencia) {
acta.setInfraccion_Referencia(new String(ch, start, length).trim());
bInfraccion_Referencia = false;
} else if (bInfraccion_Fec_Hora_Labrada) {
acta.setFec_Hora_Labrada(new String(ch, start, length).trim());
bInfraccion_Fec_Hora_Labrada = false;
} else if (bFec_Vencimiento) {
acta.setFec_Vencimiento(new String(ch, start, length).trim());
bFec_Vencimiento = false;
} else if (bRetiene_Licencia) {
acta.setRetiene_Licencia(new String(ch, start, length).trim());
bRetiene_Licencia = false;
} else if (bRetene_Vehiculo) {
acta.setRetene_vehiculo(new String(ch, start, length).trim());
bRetene_Vehiculo = false;
}else if (bTipoVehiculo) {
acta.setTipo_Vehiculo(new String(ch, start, length).trim());
bTipoVehiculo = false;
} else if (bTipoPatente) {
acta.setTipo_Patente(new String(ch, start, length).trim());
bTipoPatente = false;
} else if (bConduccionPeligrosa) {
acta.setConduccion_Peligrosa(new String(ch, start, length).trim());
bConduccionPeligrosa = false;
} else if (bDominio) {
acta.setDominio(new String(ch, start, length).trim());
bDominio = false;
} else if (bMarca) {
acta.setMarca(new String(ch, start, length).trim());
bMarca = false;
}else if (bColor) {
acta.setColor(new String(ch, start, length).trim());
bColor = false;
} else if (bSinTitular) {
acta.setSinTitular(new String(ch, start, length).trim());
bSinTitular = false;
} else if (bTipo_Dni_Propietario) {
acta.setTipo_Dni_Propietartio(new String(ch, start, length).trim());
bTipo_Dni_Propietario = false;
} else if (bDni_propietario) {
acta.setDni_Propietario(new String(ch, start, length).trim());
bDni_propietario = false;
} else if (bNombre_Propietario) {
acta.setNombre_Propietario(new String(ch, start, length).trim());
bNombre_Propietario = false;
}else if (bApellido_Propietario) {
acta.setApellido_Propietario(new String(ch, start, length).trim());
bApellido_Propietario = false;
} else if (bRazon_Social_Propietario) {
acta.setRazon_Social_Propietario(new String(ch, start, length).trim());
bRazon_Social_Propietario = false;
} else if (bCalle_propietario) {
acta.setCalle_Propietario(new String(ch, start, length).trim());
bCalle_propietario = false;
}
}
}
xml 我正在尝试获取其值:
<SDTActaCaminera xmlns='VialMza'><Acta>
<Id_Acta>1</Id_Acta>
<Nro_Acta>K0000000001</Nro_Acta>
<Letra_Serie>989</Letra_Serie>
<Infraccion_Lugar>RUTA NACIONAL</Infraccion_Lugar>
<Infraccion_Numero_Ruta>142</Infraccion_Numero_Ruta>
<Infraccion_KmAltura>10</Infraccion_KmAltura>
<Infraccion_Referencia>Aaa</Infraccion_Referencia>
<Fec_Hora_Labrada>20/02/2018 11:55:30</Fec_Hora_Labrada>
<Fec_Vencimiento>07/03/2018</Fec_Vencimiento>
<Retiene_Licencia>N</Retiene_Licencia>
<Retiene_Vehiculo>S</Retiene_Vehiculo>
<TipoVehiculo>AUTOMOVIL</TipoVehiculo>
<TipoPatente>AGF310</TipoPatente>
<ConduccionPeligrosa>S</ConduccionPeligrosa>
<Dominio>AGF310</Dominio>
<Marca>FIAT</Marca>
<Color>ROJO</Color>
<SinTitular>N</SinTitular>
<Tipo_Dni_Propietario>DNI</Tipo_Dni_Propietario>
<Dni_Propietario>31156986</Dni_Propietario>
<Nombre_Propietario>ANDRES</Nombre_Propietario>
<Apellido_Propietario>MARCOS</Apellido_Propietario>
<Razon_Social_Propietario></Razon_Social_Propietario>
<Calle_Propietario>AAA</Calle_Propietario>
</Acta>
</SDTActaCaminera>
如您所见,标签 razon_social_propietario 是空的,它不会跳过该标签,而是保存下一个标签值(在本例中为 AAA)
你的代码当然是这样做的。
当你命中一个空标签时,startElement
和 endElement
被调用,但 characters
没有,所以当下一个元素命中时,你最终得到 两个 标志设置。
我建议您去掉所有标志,记住活动标签名称,然后在 endElement
中清除该名称。然后,您在 characters
中执行 multi-way 名称检查并根据需要进行分配。也会大大简化您的代码。
private RegistrarActaBeanReq acta = new RegistrarActaBeanReq();
private String activeName;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
activeName = qName;
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
activeName = null;
}
@Override
public void characters(char ch[], int start, int length) throws SAXException {
if (activeName == null)
return;
if (activeName.equalsIgnoreCase("id_Acta"))
acta.setId_Acta(new String(ch, start, length).trim());
else if (qName.equalsIgnoreCase("Nro_Acta"))
acta.setNro_Acta(new String(ch, start, length).trim());
else if ...
...
}
不过,我建议您改为使用 StAX 解析器。更容易使用。
问题可以分解为:
public class HandlerRegistrarActa extends DefaultHandler {
private RegistrarActaBeanReq acta = null;
private boolean bRazon_Social_Propietario = false;
private boolean bCalle_propietario = false;
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (qName.equalsIgnoreCase("id_Acta")) {
bid_Acta = true;
acta = new RegistrarActaBeanReq();
} else if (qName.equalsIgnoreCase("Razon_Social_Propietario")) {
bRazon_Social_Propietario = true;
} else if (qName.equalsIgnoreCase("Calle_propietario")) {
bCalle_propietario = true;
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
}
public void characters(char ch[], int start, int length) throws SAXException {
if (bRazon_Social_Propietario) {
acta.setRazon_Social_Propietario(new String(ch, start, length).trim());
bRazon_Social_Propietario = false;
} else if (bCalle_propietario) {
acta.setCalle_Propietario(new String(ch, start, length).trim());
bCalle_propietario = false;
}
}
}
与以下 XML:
<SDTActaCaminera xmlns='VialMza'>
<Acta>
<Razon_Social_Propietario></Razon_Social_Propietario>
<Calle_Propietario>AAA</Calle_Propietario>
</Acta>
</SDTActaCaminera>
这是您的最小、完整且可验证的示例(或简称 MCVE)。
那么,如果有一个空标签会怎样?
没有为该元素调用 characters
方法。
所以 bRazon_Social_Propietario
将保持 true
。
下次调用 characters
时,它将使用它作为 Razon_Social_Propietario
.
的值
但是已经不在那个标签里了,而是在下一个标签里。
要解决这个问题,您必须取消设置 endElement
:
中的布尔值
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equalsIgnoreCase("Razon_Social_Propietario")) {
bRazon_Social_Propietario = false;
} else if (qName.equalsIgnoreCase("Calle_propietario")) {
bCalle_propietario = false;
}
}
我留给您为所有属性实施此操作。
我正在尝试使用 sax 解析器获取 xm 的值,当标记为空时,像解析器一样而不是跳过该标记保存下一个标记的值,这里是我的解析器:
public class HandlerRegistrarActa extends DefaultHandler {
private RegistrarActaBeanReq acta = null;
private List<Infracciones> infracciones = null;
private Infracciones infraccion= null;
public RegistrarActaBeanReq getActa() {
return acta;
}
boolean bid_Acta = false;
boolean bNro_Acta = false;
boolean bLetra_Serie = false;
boolean bInfraccion_Lugar = false;
boolean bInfraccion_Numero = false;
boolean bInfraccion_KmAltura = false;
boolean bInfraccion_Referencia = false;
boolean bInfraccion_Fec_Hora_Labrada = false;
boolean bFec_Vencimiento = false;
boolean bRetiene_Licencia = false;
boolean bRetene_Vehiculo = false;
boolean bTipoVehiculo = false;
boolean bTipoPatente = false;
boolean bConduccionPeligrosa = false;
boolean bDominio = false;
boolean bMarca = false;
boolean bColor = false;
boolean bSinTitular = false;
boolean bTipo_Dni_Propietario = false;
boolean bDni_propietario = false;
boolean bNombre_Propietario = false;
boolean bApellido_Propietario = false;
boolean bRazon_Social_Propietario = false;
boolean bCalle_propietario = false;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if (qName.equalsIgnoreCase("id_Acta")) {
bid_Acta = true;
acta = new RegistrarActaBeanReq();
} else if (qName.equalsIgnoreCase("Nro_Acta")) {
bNro_Acta = true;
} else if (qName.equalsIgnoreCase("Letra_Serie")) {
bLetra_Serie = true;
} else if (qName.equalsIgnoreCase("Infraccion_Lugar")) {
bInfraccion_Lugar = true;
} else if (qName.equalsIgnoreCase("Infraccion_Numero_Ruta")) {
bInfraccion_Numero = true;
} else if (qName.equalsIgnoreCase("Infraccion_KmAltura")) {
bInfraccion_KmAltura = true;
} else if (qName.equalsIgnoreCase("Infraccion_Referencia")) {
bInfraccion_Referencia = true;
} else if (qName.equalsIgnoreCase("Fec_Hora_Labrada")) {
bInfraccion_Fec_Hora_Labrada = true;
} else if (qName.equalsIgnoreCase("Fec_Vencimiento")) {
bFec_Vencimiento = true;
} else if (qName.equalsIgnoreCase("Retiene_Licencia")) {
bRetiene_Licencia = true;
} else if (qName.equalsIgnoreCase("Retiene_Vehiculo")) {
bRetene_Vehiculo = true;
} else if (qName.equalsIgnoreCase("TipoVehiculo")) {
bTipoVehiculo = true;
} else if (qName.equalsIgnoreCase("TipoPatente")) {
bTipoPatente = true;
} else if (qName.equalsIgnoreCase("ConduccionPeligrosa")) {
bConduccionPeligrosa = true;
} else if (qName.equalsIgnoreCase("Dominio")) {
bDominio= true;
} else if (qName.equalsIgnoreCase("Marca")) {
bMarca = true;
} else if (qName.equalsIgnoreCase("Color")) {
bColor = true;
} else if (qName.equalsIgnoreCase("SinTitular")) {
bSinTitular = true;
} else if (qName.equalsIgnoreCase("Tipo_Dni_Propietario")) {
bTipo_Dni_Propietario = true;
} else if (qName.equalsIgnoreCase("Dni_propietario")) {
bDni_propietario = true;
} else if (qName.equalsIgnoreCase("Nombre_Propietario")) {
bNombre_Propietario = true;
} else if (qName.equalsIgnoreCase("Apellido_Propietario")) {
bApellido_Propietario = true;
} else if (qName.equalsIgnoreCase("Razon_Social_Propietario")) {
bRazon_Social_Propietario = true;
} else if (qName.equalsIgnoreCase("Calle_propietario")) {
bCalle_propietario = true;
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
}
@Override
public void characters(char ch[], int start, int length) throws SAXException {
if (bid_Acta) {
acta.setId_Acta(new String(ch, start, length).trim());
bid_Acta = false;
} else if (bNro_Acta) {
acta.setNro_Acta(new String(ch, start, length).trim());
bNro_Acta = false;
} else if (bLetra_Serie) {
acta.setLetra_Serie(new String(ch, start, length).trim());
bLetra_Serie = false;
} else if (bInfraccion_Lugar) {
acta.setInfraccion_Lugar(new String(ch, start, length).trim());
bInfraccion_Lugar = false;
} else if (bInfraccion_Numero) {
acta.setInfraccion_Numero_Ruta(new String(ch, start, length).trim());
bInfraccion_Numero = false;
} else if (bInfraccion_KmAltura) {
acta.setInfraccion_KmAltura(new String(ch, start, length).trim());
bInfraccion_KmAltura = false;
}else if (bInfraccion_Referencia) {
acta.setInfraccion_Referencia(new String(ch, start, length).trim());
bInfraccion_Referencia = false;
} else if (bInfraccion_Fec_Hora_Labrada) {
acta.setFec_Hora_Labrada(new String(ch, start, length).trim());
bInfraccion_Fec_Hora_Labrada = false;
} else if (bFec_Vencimiento) {
acta.setFec_Vencimiento(new String(ch, start, length).trim());
bFec_Vencimiento = false;
} else if (bRetiene_Licencia) {
acta.setRetiene_Licencia(new String(ch, start, length).trim());
bRetiene_Licencia = false;
} else if (bRetene_Vehiculo) {
acta.setRetene_vehiculo(new String(ch, start, length).trim());
bRetene_Vehiculo = false;
}else if (bTipoVehiculo) {
acta.setTipo_Vehiculo(new String(ch, start, length).trim());
bTipoVehiculo = false;
} else if (bTipoPatente) {
acta.setTipo_Patente(new String(ch, start, length).trim());
bTipoPatente = false;
} else if (bConduccionPeligrosa) {
acta.setConduccion_Peligrosa(new String(ch, start, length).trim());
bConduccionPeligrosa = false;
} else if (bDominio) {
acta.setDominio(new String(ch, start, length).trim());
bDominio = false;
} else if (bMarca) {
acta.setMarca(new String(ch, start, length).trim());
bMarca = false;
}else if (bColor) {
acta.setColor(new String(ch, start, length).trim());
bColor = false;
} else if (bSinTitular) {
acta.setSinTitular(new String(ch, start, length).trim());
bSinTitular = false;
} else if (bTipo_Dni_Propietario) {
acta.setTipo_Dni_Propietartio(new String(ch, start, length).trim());
bTipo_Dni_Propietario = false;
} else if (bDni_propietario) {
acta.setDni_Propietario(new String(ch, start, length).trim());
bDni_propietario = false;
} else if (bNombre_Propietario) {
acta.setNombre_Propietario(new String(ch, start, length).trim());
bNombre_Propietario = false;
}else if (bApellido_Propietario) {
acta.setApellido_Propietario(new String(ch, start, length).trim());
bApellido_Propietario = false;
} else if (bRazon_Social_Propietario) {
acta.setRazon_Social_Propietario(new String(ch, start, length).trim());
bRazon_Social_Propietario = false;
} else if (bCalle_propietario) {
acta.setCalle_Propietario(new String(ch, start, length).trim());
bCalle_propietario = false;
}
}
}
xml 我正在尝试获取其值:
<SDTActaCaminera xmlns='VialMza'><Acta>
<Id_Acta>1</Id_Acta>
<Nro_Acta>K0000000001</Nro_Acta>
<Letra_Serie>989</Letra_Serie>
<Infraccion_Lugar>RUTA NACIONAL</Infraccion_Lugar>
<Infraccion_Numero_Ruta>142</Infraccion_Numero_Ruta>
<Infraccion_KmAltura>10</Infraccion_KmAltura>
<Infraccion_Referencia>Aaa</Infraccion_Referencia>
<Fec_Hora_Labrada>20/02/2018 11:55:30</Fec_Hora_Labrada>
<Fec_Vencimiento>07/03/2018</Fec_Vencimiento>
<Retiene_Licencia>N</Retiene_Licencia>
<Retiene_Vehiculo>S</Retiene_Vehiculo>
<TipoVehiculo>AUTOMOVIL</TipoVehiculo>
<TipoPatente>AGF310</TipoPatente>
<ConduccionPeligrosa>S</ConduccionPeligrosa>
<Dominio>AGF310</Dominio>
<Marca>FIAT</Marca>
<Color>ROJO</Color>
<SinTitular>N</SinTitular>
<Tipo_Dni_Propietario>DNI</Tipo_Dni_Propietario>
<Dni_Propietario>31156986</Dni_Propietario>
<Nombre_Propietario>ANDRES</Nombre_Propietario>
<Apellido_Propietario>MARCOS</Apellido_Propietario>
<Razon_Social_Propietario></Razon_Social_Propietario>
<Calle_Propietario>AAA</Calle_Propietario>
</Acta>
</SDTActaCaminera>
如您所见,标签 razon_social_propietario 是空的,它不会跳过该标签,而是保存下一个标签值(在本例中为 AAA)
你的代码当然是这样做的。
当你命中一个空标签时,startElement
和 endElement
被调用,但 characters
没有,所以当下一个元素命中时,你最终得到 两个 标志设置。
我建议您去掉所有标志,记住活动标签名称,然后在 endElement
中清除该名称。然后,您在 characters
中执行 multi-way 名称检查并根据需要进行分配。也会大大简化您的代码。
private RegistrarActaBeanReq acta = new RegistrarActaBeanReq();
private String activeName;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
activeName = qName;
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
activeName = null;
}
@Override
public void characters(char ch[], int start, int length) throws SAXException {
if (activeName == null)
return;
if (activeName.equalsIgnoreCase("id_Acta"))
acta.setId_Acta(new String(ch, start, length).trim());
else if (qName.equalsIgnoreCase("Nro_Acta"))
acta.setNro_Acta(new String(ch, start, length).trim());
else if ...
...
}
不过,我建议您改为使用 StAX 解析器。更容易使用。
问题可以分解为:
public class HandlerRegistrarActa extends DefaultHandler {
private RegistrarActaBeanReq acta = null;
private boolean bRazon_Social_Propietario = false;
private boolean bCalle_propietario = false;
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (qName.equalsIgnoreCase("id_Acta")) {
bid_Acta = true;
acta = new RegistrarActaBeanReq();
} else if (qName.equalsIgnoreCase("Razon_Social_Propietario")) {
bRazon_Social_Propietario = true;
} else if (qName.equalsIgnoreCase("Calle_propietario")) {
bCalle_propietario = true;
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
}
public void characters(char ch[], int start, int length) throws SAXException {
if (bRazon_Social_Propietario) {
acta.setRazon_Social_Propietario(new String(ch, start, length).trim());
bRazon_Social_Propietario = false;
} else if (bCalle_propietario) {
acta.setCalle_Propietario(new String(ch, start, length).trim());
bCalle_propietario = false;
}
}
}
与以下 XML:
<SDTActaCaminera xmlns='VialMza'>
<Acta>
<Razon_Social_Propietario></Razon_Social_Propietario>
<Calle_Propietario>AAA</Calle_Propietario>
</Acta>
</SDTActaCaminera>
这是您的最小、完整且可验证的示例(或简称 MCVE)。
那么,如果有一个空标签会怎样?
没有为该元素调用 characters
方法。
所以 bRazon_Social_Propietario
将保持 true
。
下次调用 characters
时,它将使用它作为 Razon_Social_Propietario
.
的值
但是已经不在那个标签里了,而是在下一个标签里。
要解决这个问题,您必须取消设置 endElement
:
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equalsIgnoreCase("Razon_Social_Propietario")) {
bRazon_Social_Propietario = false;
} else if (qName.equalsIgnoreCase("Calle_propietario")) {
bCalle_propietario = false;
}
}
我留给您为所有属性实施此操作。