从 XMLBeans 接收事件,定制 XMLBean POJO,把数据模型的更改通知观察器

Java POI解析Excel的跨Sheet读取数据验证下拉值 存在一个Excel文件,其中有列数据是下拉选择,且下拉的来源是在另外一个Sheet中 这个时候,我们使用POI对其进行解析,想获得数据验证的个数:sheet.getDataValidations() public static void main(String[] args) throws Exception { String filePath = "/Users/fujiexiang/ExcelWorkbook.xlsx"; Workbook work. 阅读详情

XML 模式描述 XML 的类型、元素和结构。Simple API for XML(SAX)、Document Object Model(DOM)和 XML Object Model(XOM)等一般性工具很难简便地使用这些信息。XMLBeans 这种数据绑定框架可以从 XML 模式创建 POJO,允许快速地读取、操作和写 XML。

在处理 POJO 时,尤其是胖客户机,需要知道对象什么时候发生变化 — 通常称为事件(eventing) 或通知(notification)。事件是 Model View Controller(MVC)和 Model 2 模式的核心组件,这些模式的主要意图是在图形用户界面(GUI)代码和模型代码之间形成松散耦合。我们将以 Sudoku 游戏为例,讲解如何用 XMLBeans 扩展在基于 XML 的 Java 应用程序中添加事件功能。

Sudoku 是一个 9 乘 9 的网格,它划分为 9 个 3 乘 3 的子网格。在游戏开始时,一些单元格已经填上了 1 到 9 的数字。玩家的任务是根据以下限制填写余下的单元格:

  1. 所有单元格必须包含 1 到 9 的数字。这由 XMLBeans 生成的代码处理。
  2. 每行中的所有 9 个单元格必须是惟一的。
  3. 每列中的所有 9 个单元格必须是惟一的。
  4. 每个子网格中的所有 9 个单元格必须是惟一的。

图 1 给出 Sudoku 的游戏板。我们开发了一个应用程序,它使用 XMLBeans 事件功能检验是否满足限制 2-4。如果不满足某个限制,就更新视图,把与限制冲突的单元格显示为红色。


图 1. Sudoku 游戏板示例
Sudoku 游戏板示例

关于 Sudoku 的历史和策略的更多信息参见 参考资料。

过程流概述

Observer 设计模式可以把更改通知给对此感兴趣的对象。本文中描述的 XMLBeans 事件代码是这种设计模式的实例。这种模式的思想是,允许对象进行注册,请求在运行时获得 XmlObject 中模型更改的通知。按照这种方式,就可以在 Sudoku 单元格上连接监听器,对每个更改进行检验。

XMLBeans 允许使用一个配置文件(也称为 XSDCONFIG 文件)定制代码生成过程。XSDCONFIG 文件包含以下方面的 XML 配置:

  1. Java 包的名称空间映射
  2. Java 类的类型和元素 QName 映射
  3. 在生成的代码中添加方法
  4. 在模型更改之前和之后添加实现

如果在编译时知道对更改感兴趣的对象,第 4 项 就支持为它们生成事件。但糟糕的是,通常不会提前知道这些对象。关于 XSDCONFIG 文件内容的更多信息参见 参考资料。

为了启用事件,需要实现 第 3 项 和 第 4 项。这需要完成以下四个步骤:

  1. 编写一个接口扩展,从而允许向 XmlObject 注册监听器。
  2. 编写一个 PrePostSet 扩展,它把模型更改通知监听器。
  3. 创建一个包含必要配置信息的 XSDCONFIG 文件。
  4. 把关于 XSDCONFIG 文件的信息告诉 XMLBeans 实用程序 scomp。

编写一个接口扩展

XMLBeans 的接口扩展特性允许在生成的 POJO 中添加具有定制实现的方法。XMLBeans 要求创建一个接口,并为这个接口中的每个方法提供静态的实现。我们创建的接口放在 com.ibm.wsrc.xmlbeans.IModelChangeEmitter 中,它包含四个方法,见 清单 1。


清单 1. com.ibm.wsrc.xmlbeans.IModelChangeEmitter.java

public   interface  IModelChangeEmitter  {
  
public void fireModelChangeEvent(ModelChangeEvent event);
  
public void addModelChangeListener(IModelChangeListener modelChangeListener);
  
public void removeModelChangeListener(IModelChangeListener modelChangeListener);
  
public boolean hasModelChangeListeners();
}

这个接口有两个生命周期管理监听器方法, addModelChangeListener() 和 removeModelChangeListener();一个监听器检测,hasModelChangeListeners(),以及一个实用程序方法,fireModelChangeEvent(),这个方法用来把模型更改通知注册的所有监听器。

当任何过程调用这些方法之一时,XMLBeans 把调用这个方法的 XmlObject 和参数传递给一个静态实现。在这个示例中,静态实现放在 com.ibm.xmlbeans.eventing.ModelChangeEmitterHandler.java 中。因为这是一个静态实现,而且不能在 XmlObject 中存储实例变量,所以需要在别处存储对更改感兴趣的对象的列表。在这个实现中,列表存储在一个静态 HashMap 中。清单 2 给出这个类中的 Java 代码内容。


清单 2. com.ibm.wsrc.xmlbeans.ModelChangeEmitterHandler.java

public   class  ModelChangeEmitterHandler  {
  
private static HashMap<XmlObject, LinkedList<IModelChangeListener>> listeners =
    
new HashMap<XmlObject, LinkedList<IModelChangeListener>>();

  
public static void fireModelChangeEvent(XmlObject xo, ModelChangeEvent event) {
    LinkedList
<IModelChangeListener> list = listeners.get(xo);
    
if (list == null)
      
return;

    
for (IModelChangeListener listener : list)
      listener.modelChange(event);
  }


  
public static void addModelChangeListener(XmlObject xo,
    IModelChangeListener modelChangeListener) 
{
    LinkedList
<IModelChangeListener> list = listeners.get(xo);
    
if (list == null) {
      list 
= new LinkedList<IModelChangeListener>();
      listeners.put(xo, list);
    }

    list.add(modelChangeListener);
  }


  
public static void removeModelChangeListener(XmlObject xo,
    IModelChangeListener modelChangeListener) 
{
    LinkedList
<IModelChangeListener> list = listeners.get(xo);
    
if (list == null)
      
return;
    list.remove(modelChangeListener);

    
// remove references of list and XmlObject
    if (list.isEmpty())
      listeners.remove(xo);
  }


  
public static boolean hasModelChangeListeners(XmlObject xo) {
    
return listeners.containsKey(xo);
  }

}

addModelChangeListener() 方法很好地演示了如何使用监听器列表。addModelChangeListener() 方法首先检查是否已经为这个 XmlObject 注册了监听器列表,如果这个列表不存在,就创建它。最后,在这个列表中添加监听器。

编写 PrePostSet 扩展

PrePostSet 扩展使我们能够在 XMLBeans 中添加定制的处理。我们使用一个静态类,其中包含在 XmlObject 更改之前和之后运行的方法,见 清单 3。


清单 3. PrePostSet 扩展伪代码

if  (PrePostSetExtension.preSet())
  updateXmlObject();
PrePostSetExtension.postSet();

静态方法 preSet() 和 postSet() 具有相同的签名:*Set(int opType, XmlObject xo, QName propertyName, boolean isAttr, int index)。初看上去,postSet() 方法似乎可以包含所有事件代码。但是,postSet() 方法并不掌握触发事件所需的所有信息。postSet() 需要向注册的所有监听器触发一个事件,事件包含更新的对象、更新的操作、更新之前的值和目前的值。在 postSet() 方法中不知道以前的值。因此,需要静态地存储以前的对象内容。

以前的值存储在静态 HashMap oldValues 中。在 preSet() 方法中,把原来的值复制到这个 HashMap 中;在 postSet() 方法中,执行实际的事件触发操作。清单 4 给出 preSet() 方法的代码。


清单 4. com.ibm.xmlbeans.eventing.ModelChangePrePostHandler.preSet()

public   static   boolean  preSet( int  opType, XmlObject xo, QName propertyName,
  
boolean  isAttr,  int  index)  {
  IModelChangeEmitter emitter 
= (IModelChangeEmitter)xo;
  
if (!emitter.hasModelChangeListeners())
    
return true;

  
// get the child that will be changed
  XmlObject oldXO = null;
  
if (isAttr)
    oldXO 
= xo.selectAttribute(propertyName);
  
else {
    
switch (opType) {
      
case PrePostExtension.OPERATION_SET:
      
case PrePostExtension.OPERATION_REMOVE:
        oldXO 
= getChildXO(xo, propertyName, index);
        
break;
      
case PrePostExtension.OPERATION_INSERT:
        
break;
    }

  }


  
// store the old value
  int hash = hashCode(xo, propertyName, isAttr, index);
  Object oldValue 
= null;
  
if (oldXO == null)
    oldValue 
= null;
  
else if (oldXO instanceof SimpleValue) {
    oldValue 
= ((SimpleValue)oldXO).getObjectValue();
    
if (oldValue instanceof XmlObject)
      oldValue 
= ((XmlObject)oldValue).copy();
    }
 else
      oldValue 
= oldXO.copy();

  oldValues.put(hash, oldValue);

  
return true;
}

在这个方法中,代码检查模型对象上是否连接了任何监听器。如果有监听器,就缓存当前的属性值。如果它不是属性,就调用实用程序方法 getChildXO()。最后,如果它是非常量 XmlObject,就复制它的值。然后,把副本或原来的值存储在 oldValues HashMap 中。清单 5 给出 postSet() 方法的代码。


清单 5. com.ibm.xmlbeans.eventing.ModelChangePrePostHandler.postSet()

public   static   boolean  postSet( int  opType, XmlObject xo, QName propertyName,
  
boolean  isAttr,  int  index)  {
  IModelChangeEmitter emitter 
= (IModelChangeEmitter)xo;
  
if (!emitter.hasModelChangeListeners())
    
return true;

  
// get the old value;
  int hash = hashCode(xo, propertyName, isAttr, index);
  Object oldValue 
= oldValues.get(hash);
  oldValues.remove(hash);

  ModelChangeEvent.Action action 
= ModelChangeEvent.Action.UPDATE;

  
// get the new xml object
  XmlObject newXO = null;
  
if (isAttr)
    newXO 
= xo.selectAttribute(propertyName);
  
else {
    
switch (opType) {
      
case PrePostExtension.OPERATION_SET:
        newXO 
= getChildXO(xo, propertyName, index);
        
break;
      
case PrePostExtension.OPERATION_INSERT:
        XmlObject[] children 
= xo.selectChildren(propertyName);

        
// on an insert, it is always the last element
        newXO = children[children.length - 1];
        action 
= ModelChangeEvent.Action.CREATE;
        
break;
      
case PrePostExtension.OPERATION_REMOVE:
        action 
= ModelChangeEvent.Action.DELETE;
        
break;
    }

  }


  
// get the new value
  Object newValue = null;
  
if (newXO == null)
    newValue 
= null;
  
else if (newXO instanceof SimpleValue)
    newValue 
= ((SimpleValue)newXO).getObjectValue();
  
else
    newValue 
= newXO;

  
// if newValue != oldValue
  if (((newValue == null) && (oldValue != null)) || ((newValue != null)
    
&& (!newValue.equals(oldValue))))
    emitter.fireModelChangeEvent(
new ModelChangeEvent(propertyName,
      emitter, oldValue, newValue, action, index));
  
return true;
}

postSet() 方法首先检查是否有任何监听器连接这个 XmlObject。如果有,代码就从 oldValues HashMap 获取原来的值。它从当前的 XmlObject 获取当前值并赋值给 newValue 变量。最后,postSet() 检查 oldValue,确定它与 newValue 不相等。XmlObject 创建并触发一个模型更改事件。清单 6 给出实用程序方法。


清单 6. com.ibm.xmlbeans.eventing.ModelChangePrePostHandler 实用程序方法

private   static  XmlObject getChildXO(XmlObject xo, QName propertyName,  int  index)  {
  XmlObject childXO 
= null;
  XmlObject[] values 
= xo.selectChildren(propertyName);
  
if (values.length != 0) {
    
if (index == -1)
      childXO 
= values[0];
    
else if (index < values.length)
      childXO 
= values[index];
  }

  
return childXO;
}


private   static   int  hashCode(XmlObject xo, QName propertyName,  boolean  isAttr,  int  index)  {
  
final int prime = 31;
  
int result = 1;
  result 
= prime * result + index;
  result 
= prime * result + (isAttr ? 1231 : 1237);
  result 
= prime * result + ((propertyName == null) ? 0 : propertyName.hashCode());
  result 
= prime * result + ((xo == null) ? 0 : xo.hashCode());
  
return result;
}

getChildXO() 方法从 XmlObject 获取一个属性值。如果返回多个值,就使用 selectChildren() 方法并获取适当的子元素。hashCode() 方法为 XmlObject 和 XmlObject 的属性计算一个惟一的散列值;Eclipse 会自动创建这个方法。

配置 XMLBeans 的代码生成

为了在 XMLBeans 上实现事件,需要使用并配置接口扩展特性和 PrePostSet 扩展特性。清单 7 给出 XSDCONFIG 文件。


清单 7. XMLBeans 事件的 XSDCONFIG 文件

< xb:config  xmlns:xb ="http://xml.apache.org/xmlbeans/2004/02/xbean/config" >
  
< xb:extension  for ="*" >
    
< xb:interface  name ="com.ibm.xmlbeans.eventing.IModelChangeEmitter" >
      
< xb:staticHandler >
        com.ibm.xmlbeans.eventing.ModelChangeEmitterHandler
      
</ xb:staticHandler >
    
</ xb:interface >
  
</ xb:extension >

  
< xb:extension  for ="*" >
    
< xb:prePostSet >
      
< xb:staticHandler >
        com.ibm.xmlbeans.eventing.ModelChangePrePostHandler
      
</ xb:staticHandler >
    
</ xb:prePostSet >
  
</ xb:extension >
</ xb:config >

xb:config 的第一个 xb:extension 元素包含接口扩展的配置。在这里,它为生成的所有 XmlObject 定义接口来扩展 IModeChangeEmitter。XMLBeans 将运行 ModelChangeEmitterHandler 中的实现。

xb:config 的第二个 xb:extension 元素包含 PrePostSet 扩展的配置。它让 XMLBeans 在修改属性之前和之后分别调用 ModelChangePrePostHandler 类中的 preSet() 和 postSet()。

最后,为了把配置文件输入生成器,需要在 scomp 的最后一个参数中指定 XSDCONFIG 文件。对于这个 Sudoku 游戏,在一个 Java 类中指定这个参数,见 清单 8。


清单 8. com.ibm.xmlbeans.generator.SudokuSchemaGenerator.java

public   class  SudokuSchemaGenerator  {
  
public static void main(String[] args) {
    String[] xmlBeanArgs 
= new String[] {
      
"-d", "xb_bin",
      
"-src", "xb_src",
      
"-out", "lib/sudokuXB.jar",
      
"-javasource", "1.5",
      
"schema/sudokuXBE.xsd",
      
"schema/eventing.xsdconfig"
    }
;
    org.apache.xmlbeans.impl.tool.SchemaCompiler.main(xmlBeanArgs);
  }

}

关于 scomp 和命令行参数的更多信息参见 参考资料。

在运行这个命令之后,现在就有了来自 sudokuXBE.xsd 的 POJO,这些 POJO 在发生更改时可以通知对更改感兴趣的对象。


创建 Sudoku 游戏 RCP 应用程序

Sudoku 游戏是一个 RCP 应用程序,当用户在一个单元格中填写了不合适的值时,这个程序会通知用户。程序会根据行、列和子网格中的其他单元格检查值是否符合限制。如果有任何值不符合限制,就把单元格显示为红色,见 图 2。


图 2. Sudoku 游戏
Sudoku 游戏的两个屏幕图

按照以下步骤实现这个游戏的图形用户界面(UI):

  1. 创建一个代表游戏板的 Sudoku 模式。
  2. 从这个模式生成一组包含事件功能的 XMLBeans。
  3. 使用生成的 XMLBeans 创建一个 MVC 风格的应用程序。

这个应用程序的设计原则是消除视图和模型之间的耦合。控制器是 Standard Widget Toolkit(SWT)键监听器,它首先修改模型。然后,模型把更改通知检验器。检验器检查它们控制的单元格是否是有效的;如果有效,它们设置有效标志。然后,框架触发另一个事件,视图(单元格)会捕捉这个事件。这会更新单元格的背景颜色。图 3 在一个流程图中显示这四个步骤。


图 3. Sudoku RCP 应用程序的事件流
Sudoku RCP 应用程序的事件流

在 XML 模式中对 Sudoku 游戏进行建模

模式定义很简单,首先建立游戏板。游戏板包含 9 行和 9 列单元格,单元格只能包含 1 到 9 的值。使用这个简单的定义创建模式。图 4 所示的游戏板类型由 9 个行类型的元素组成。


图 4. BoardType XML 模式类型
BoardType XML 模式类型

然后定义行类型,见 图 5。这样就足以定义整个 9 乘 9 的 Sudoku 网格。


图 5. RowType XML 模式类型
RowType XML 模式类型

行类型包含 9 个单元格类型的元素。通过把行类型划分为 9 个单元格类型的元素,就可以定义行中每个单元格中的值,见 图 6。


图 6. CellType XML 模式类型
CellType XML 模式类型

单元格类型是一个简单的元素,其中可以包含 1 到 9 的值和点号(.),点号表示没有值。单元格类型还有一个属性,它根据行、列和子网格限制表示这个单元格是否有效,见 图 7。


图 7. CellStringType XML 模式类型
CellStringType XML 模式类型

单元格字符串类型进一步定义单元格,把其中的值限制为 1 到 9 的值和点号。

生成 XMLBeans

通过使用这个模式定义和 配置 XMLBeans 的代码生成 中定义的 XMLBeans 生成代码,生成一组 POJO,它们代表这个模式并包含事件功能,当模型发生任何更改时,可以通知 UI。

编写应用程序 UI

由于事件功能是生成的 XMLBeans 的组成部分,所以可以按照典型的 MVC 风格编写 UI。模型的视图是使用 Eclipse 平台开发的。这个 RCP 应用程序本质上是一个 Eclipse 插件,并在这个 Eclipse 插件启动时初始化一个视图。在创建每个 SWT 文本部件并把它添加到视图中时,通过 text.addKeyListener() 方法调用添加一个键监听器。这样,当用户在空单元格中输入值时,就可以截取按键操作。见 清单 9。


清单 9. com.ibm.xmlbeans.tutorial.View.addKeyListeners().new KeyAdapter() {...}

public   void  keyPressed(KeyEvent e)  {
  
switch (e.keyCode) {
    
case '1':
    
case '2':
    
case '3':
    
case '4':
    
case '5':
    
case '6':
    
case '7':
    
case '8':
    
case '9':
      
if (text.getEditable()) {
        
final CellStringType.Enum newValue =
          CellStringType.Enum.forString(String.valueOf(e.character));
        Job job 
= new Job("Run Validation") {
          
protected IStatus run(IProgressMonitor arg0) {
            XbeUtilities.getCell(Activator.getDefault().getBoard(), myRow, myCol)
              .setCellValue(newValue);
            
return Status.OK_STATUS;
          }

        }
;
        text.setText(String.valueOf(e.character));
        job.schedule();
      }

      
break;
    
case SWT.BS:
    
case SWT.DEL:
    
case '.':
    
case ' ':
      
if (text.getEditable()) {
        Job job 
= new Job("Run Validation") {
          
protected IStatus run(IProgressMonitor arg0) {
            XbeUtilities.getCell(Activator.getDefault().getBoard(), myRow, myCol)
              .setCellValue(CellStringType.X);
            
return Status.OK_STATUS;
          }

        }
;
        job.schedule();
        text.setText(
" ");
      }

      
break;
    
// ... arrow navigation code ...
  }

  e.doit 
= false;
}

然后通过 setCellValue(newValue) 调用设置模型中的值。这个调用会更新 XML 模式定义的模型。XMLBeans 事件代码触发一个事件,通知所有监听器模型已经更改了。

事件模型的关键部分是,根据单元格在行、列和子网格中的位置,通知单元格的有效性。在 modelChange(ModelChangeEvent event) 方法中,调用 runValidation() 方法来检验单元格的值,见 清单 10。


清单 10. com.ibm.xmlbeans.listeners.CellValidatorListener.modelChange(ModelChangeEvent)

public   void  modelChange(ModelChangeEvent event)  {
  
if (XbeUtilities.CELLVALUE_QNAME.equals(event.getPropertyName())) {
    
// if the current cell value is set
    if (!CellStringType.X.equals(cell.getCellValue())) {
      
if (cell.equals(event.getSource())) {
        
// run manual validation
        int count = runValidation();
        numInvalid 
= count;
      }
 else {
        
// another cell
        if (cell.getCellValue().equals(CellStringType.Enum.forString(
          (String)event.getNewValue())))
          numInvalid
++;
        
else {
          
if (cell.getCellValue().equals(CellStringType.Enum.forString(
            (String)event.getOldValue())))
            numInvalid
--;
        }

      }

  }
 else if (cell.equals(event.getSource()))
    numInvalid 
= 0;

  
if (numInvalid == 0)
    cell.setValid(
true);
  
else if (numInvalid < 0) {
    Activator.getDefault().getLog().log(
      
new Status(IStatus.WARNING, Activator.PLUGIN_ID,
      
"Cell validator has a negative number of invalid cells.  This is impossible."));
  }
 else
    cell.setValid(
false);
  }

}

可以看到,首先检查更改了哪个属性。在 清单 10 中,它应该是 CELLVALUE_QNAME 属性。如果这个单元格是事件源,那么调用 runValidation() 来针对所有条件执行检验。但是,如果事件源是另一个单元格,那么只需检查值是否不等于新值。如果相等,就需要把 numInvalid 加 1。如果值等于原来的值,就需要把 numInvalid 减 1。最后,如果 numInvalid 是零,就可以通过 cell.setValid(true) 把单元格的有效标志设置为 true。否则,需要通过 cell.setValid(false) 把单元格的有效标志设置为 false。通过这些调用设置单元格的有效标志之后,XMLBeans 事件机制触发另一个事件。视图监听器处理这个事件,更新单元格的背景颜色,见 清单 11。


清单 11. com.ibm.xmlbeans.tutorial.View.addTextNotifier(...).new IModelChangeListener() {...}.modelChange(ModelChangeEvent)

public   void  modelChange(ModelChangeEvent event)  {
  
if (XbeUtilities.VALID_QNAME.equals(event.getPropertyName())) {
    
// might not be in the display thread, need to run in it to
    
// modify the background!
    text.getDisplay().asyncExec(new Runnable() {
      
public void run() {
        
if (cell.getValid())
          text.setBackground(text.getDisplay().getSystemColor(SWT.COLOR_WHITE));
        
else
          text.setBackground(text.getDisplay().getSystemColor(SWT.COLOR_RED));
      }

    }
);
  }

}

可以看到,当触发 modelChange 事件时,单元格会得到通知,因为每个单元格中都添加了 modelChangeListener()。在处理这个事件时,单元格检查它是否有效,并适当地设置对应的文本部件的背景颜色。

结束语

通过使用事件,可以采用简单的编程模型,消除用户界面对模型的依赖性。因此,可以快速创建 Sudoku 游戏应用程序,并避免视图和模型之间的耦合。

可以通过使用 XMLBeans 中的两个扩展点(接口和 PrePostSet)在 XMLBeans 中添加事件功能。使用接口扩展在 XMLBeans 中添加监听器,使用 PrePostSet 扩展捕捉更改并通知相关对象。最后,通过一个配置文件把这些扩展集成到 XMLBeans 生成过程中。

下载

描述名字大小下载方法
XMLBeans 事件和 Sudoku 游戏 Eclipse 项目x-xmlbeanse/SudokuProject.zip2694KBHTTP
用 XML 描述的 Sudoku 游戏板x-xmlbeanse/SudokuBoards.zip4KBHTTP
针对 Windows 编译的 Sudoku 游戏x-xmlbeanse/SudokuApplication-Win32.zip146346KBHTTP


逐行解读Spring(一) - Xml配置解析,bean标签的解析 目录一、前言二、一个简单的示例三、源码解析1. beanDefinition注册流程2. bean标签解析四、总结 一、前言 最近在看spring源码,发现之前看的很多细节已经忘了,于是决定在看源码的过程中也把主要的流程用博客记载下来,希望自己能坚持下来吧。 spring已经发展很久,整个体系已经变得很庞大了。为了能更好的把源码看下去,我决定从最基础也是最核心的IOC开始切入,并且从最原始的xml解析开始看。面对这样一个庞大的体系,我认为从最原始的方式开始学习,才能更好的看懂它的设计和实现思路。 这一系列文 阅读详情

相关推荐

xmlbean&xmlstream

用xmlbean和xmlstream进行xml和javabean的转换案例

SelectNodes 与 XPath

<br />XPath 是 XML 的内容,这里 SelectNodes 是 C# 中 XmlDocument 或 XmlNode 的一个方法。SelectNodes 使用 XPath 来选取节点。<br />重要语法<br />SelectNodes("item")<br />从当前节点的儿子节点中选择名称为 item 的节点。<br />SelectNodes("/item")<br />从根节点的儿子节点中选择名称为 item 的节点。<br />SelectNodes("//item")<br />

leehong的BLOG 1559

arXiv订阅进阶玩法:除了邮件,还能用RSS和Python脚本打造你的专属论文追踪器

本文介绍了arXiv订阅的进阶玩法,教你如何通过RSS和Python脚本打造个性化的论文追踪器。突破传统邮件订阅的局限,实现实时更新、精准过滤和自动化管理,提升科研效率。特别适合需要高效追踪最新研究进展的学者和开发者。

weixin_26757925的博客 626

Xml让人郁闷的SelectNodes方法

SelectNodes(xpath,namespace)方法中无论是xmlDoc.SelectNodes(xpath,namespace) //假设xmlDoc为根节点,整个文档下的查询还是xmlDoc.ChildNodes[i].SelectNodes(xpath,namespace) //节点下的查询两个查询的结果一样:都会把整个文档符合xpath语法条件的都给查出来了事实上我们所要的只是要在...

weixin_34303897的博客 699

HDMI调试避坑指南:从AVI InfoFrame到通用控制包,这些DataIsland Packet细节千万别忽略

本文深入解析HDMI调试中DataIsland数据包的关键细节,包括AVI InfoFrame、通用控制包和音频时钟再生包(ACR)的配置与故障排查。通过实际案例和寄存器配置示例,帮助工程师快速定位显示异常、色彩失真和音频中断等问题,提升HDMI接口调试效率。

weixin_30897233的博客 635

Case-Based Reasoning用于RAG

在做大模型应用RAG的时候,会发现一种特殊的场景,就是基于之前的case进行回答,比如法律咨询、医疗诊断等等。这种情况的问答,需要有强有力的case支持才行,有了case支持,大模型回答会更加准确。CBR这个概念已经很久了,它是一种人工智能推理方法,它的基本思想是:遇到新问题时,先回忆相似的过去案例,再基于这些案例进行调整,得到新问题的解答。Retrieve(检索):在案例库中找到与当前问题最相似的案例。Reuse(复用):借鉴案例的解决方案来应对当前问题。

sinat_28694519的博客 938

xmlBeans xsd生成java类的 scomp命令参数

scomp -out weather.jar weather_latlong.xsd myconfig.xsdconfig Compiles a schema into XML Bean classes and metadata. Usage: scomp [opts] [dirs]* [schema.xsd]* [service.wsdl]* [config.xsdconfig]* O

zhangliao613的专栏 3049

开源Agent Skill让AI画图不再翻车:从数据到专业图表全流程

在人工智能与数据可视化交叉领域,让模型直接生成图表往往伴随字体乱码、坐标轴密集、配色失调等高频问题。Agent Skill作为一种可复用的能力封装机制,将专业绘图流程固化为标准化操作手册,从数据特征识别、图表类型决策到代码生成与渲染校验形成完整闭环。它不再依赖临时提示词的一次性发挥,而是让AI按领域专家的思维执行任务,显著提升出图质量与稳定性。这种能力在数据分析报告、运营日报、论文插图等场景具有广泛实用价值,尤其适用于需要快速产出规范化图表的工作流。本文即从这一技术范式出发,介绍一个GitHub上获得2.5

weixin_33851429的博客 948

XMLBEANS的使用总结

这几天正好研究schema文件生成javabean,再通过javabean生成、修改和删除XML,特此记录: 该文章转自:http://xiejiangbo.iteye.com/blog/582581   一、关于XML解析  XML在Java应用程序里变得越来越重要, 广泛应用于数据存储和交换. 比如我们常见的配置文件,都是以XML方式存储的. XML还应用于Java Message Se...

oceandeep1984的专栏 341

深入解析基于Fluent的蒸发冷凝相变UDF程序及其在重力热管液体蒸发冷凝变化计算中的应用

ANSYS Fluent是一款功能强大的CFD软件,广泛应用于流体流动、传热、化学反应和多相流等领域的数值模拟。Fluent提供了丰富的物理模型和求解器,支持用户自定义函数(UDF)以扩展其功能,实现更为复杂和特定的模拟需求。UDF是用C语言编写的程序,允许用户在Fluent中自定义物理模型、边界条件、源项等,以实现特定的模拟需求。在处理复杂的相变过程、非均匀物性参数或特定的热传导机制时,UDF提供了极大的灵活性和扩展性。

qq_38334677的博客 1265

服务器搭建原神私服教程

项目的稳定版分支提供了编译好的服务端程序,但是博主觉得还是用dev版本的比较好。dev版本需要自己编译的,不要听到编译这两个字就头大,相反,这个服务端的编译相当简单。把文件中的两个IP地址127.0.0.1修改为你服务器的地址,修改完成后按 esc 输入 :wq。Mongodb作为服务端的数据库使用,我们这里安装最新版的Mongodb5。注意:如果想要使用最新版的服务端,必须安装>=17版本的java。tmux可以保证你关掉控制台的时候,程序依然继续运行。至此,服务端所需要的运行环境全部配置完成。

用最简单的方式说最重要的事!服务器、存储、云计 算、A智能的大数据产品、游戏开发技术。致力于广 大开发者、政企用户、各项机构等,构建云上世界提供全方位云计算解决方案。旨在打造差异化的开放式闭环生态系统帮助用户快速构建稳定、安全的云计算环境。 1万+

使用xmlbeans根据xsd文件生成对应的jar包

使用xmlbeans根据xsd文件生成对应的jar包

阿狸_桃子 4329

【报错解决】OpenClaw 报错 EACCES: permission denied:安装权限不足

本文针对国产操作系统环境下使用 npm 安装 OpenClaw 时出现的 EACCES 权限错误,提供了专业解决方案。文章首先分析了问题本质是 npm 全局安装路径与 Linux 权限模型的冲突,然后给出三种解决方案:1)配置用户级 npm 全局目录(推荐);2)使用 nvm 管理 Node.js;3)临时使用 sudo(不推荐)。特别强调在企业环境中应避免使用 root 权限安装,并详细说明了如何正确设置用户级 npm 路径,确保符合生产环境的安全审计要求。该方案同样适用于 OpenEuler、OpenC

博客 3190

Xml中SelectSingleNode()方法的使用

最常见的XML数据类型有:Element, Attribute,Comment, Text. Element, 指形如<Name>Tom<Name>的节点。它可以包括:Element, Text, Comment, ProcessingInstruction, CDATA, and EntityReference. Attribute, 指在<Employee >中的粗体部分。 Comment,指形如:<!-- my comment --> 的...

WarGames_dc的博客 1万+

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

配置XMLBeans

配置XMLBeans时间:2005-03-10作者:Hetal Shah浏览次数: 961 本文关键字:配置, XMLBeans 文章工具 推荐给朋友 打印文章XMLBeans 1.0.3最强大的功能之一是可通过提供配置文件定制代码生成。在灵活性、可重用性、简化代码和维护方面,XMLBeans的功能带来了许多益处。因为任何企业应用程序相当大部分的成本都在于维护方面,所以从长远来看,XMLB

陈建慧程序人生 1572

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

问题:jQuery中遍历XML文件时候,获取子节点children不支持的情况(已解决)

问题描述: 今天在写一个基于 jquery 的读取xml文件的程序时候,需要遍历xml的节点。 代码片段如下: 1 function parse_xml_node(parent,result){ 2 // result[$(parent)[0].nodeName] = {}; 3 if( false == ($(parent)[0].nodeName ...

aiqianqi1796的博客 478

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

java读XML到实体bean中

需求: java读XML文档到一个实体bean中 给定一个XML文档,将所有的节点,封装到一个实体中,然后,传XML文件名到程序,将该文件的内容读到实体bean中,返回实体。 xml文档的内容 select * from table {} 根据上面的内容,创建一个实体bean(BO形式),值得注意的是XML中有很多节点和属性

Abubu123的博客 1320

Spring XML Bean 定义的加载和注册

前言 本篇文章主要介绍 Spring IoC 容器怎么加载 bean 的定义元信息。 下图是一个大致的流程图: 第一次画图,画的有点烂。???? 正文 首先定义一个简单的 POJO,如下: public class User { private Long id; private String name; public Long getId() { return id; } public voi...

weixin_46577306的博客 473

使用XMLBeans绑定XML-java数据

XMLBeans提供了底层XML数据的对象视图,同时还能访问原始的XML信息集合。通过递增的解除封送xml数据和高效的访问XML 模式内置数据类型的方法,XMLBeans交付了较好的性能。下面两种特性几乎百分之百的支持XML模式,并在操作数据期间定时验证XML数据 ,从而使XMLBeans非常适用于XML-Java 数据绑定。   XMLBeans目前处于 Apache项目的孵化过程中...

agol83082486的博客 314

spring容器-04 从xml中获取bean

源码参考:github上的code4craft/tiny-spring项目。 tiny-spring-step-4-config-beanfactory-with-xml 文章目录tiny-spring-step-4-config-beanfactory-with-xml源码解析BeanDefinitionReaderAbstractBeanDefinitionReaderXmlBeanDefinitionReader测试 源码解析 前面三篇bean的定义都是在Java中完成,现在改为从xml中解析获取be

头皮发麻 462

依赖排查问题总结

问题: 最近公司在将配置信息由UCM转到Apollo,因此需要去掉UCM项目的依赖包。在清理过程中,发现项目启动,一直报java.lang.NoClassDefFoundError: com/aliyun/oss/OSSClient错误。 分析: 发现本地是有相关的依赖的。 并且我还手动引用了: <dependency> <groupId>org.apache.httpcomponents</groupId>

qq_33642970的博客 1699

类加载链接初始化

一类生命周期 Loading Linking(Verification、Preparation、Resolution) Initializing c353.png 二类加载器 1图解 c354.png 2代码 package jvm; public class T002_ClassLoadLevel { public static void main(String[] args) { System.out.println(String.class...

实践求真知 1326

xml请求解析出错[object, object]解决

问题:有一个网关判断条件–>金额>45000 我就在分支名称里写了**">45000"** 让它怎么解析 > 命名任何地方都不要出现**> <**之类的符号,不然无法解析 ...

finally_flx的博客 915
上一篇: XFire 入门,轻松将 POJO 发布成 Web 服务
下一篇: 使用 XML 实现 REST 式的 SOA,简化面向服务和 XML 序列化
phantomhu
博客等级 码龄23年 70粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值