代码之家  ›  专栏  ›  技术社区  ›  skaffman

使用模式根据模式对XML文档的元素进行重新排序

  •  6
  • skaffman  · 技术社区  · 16 年前

    XSOM


    <A>
       <Y/>
       <X/>
    </A>
    

    <A> <X> 随后是a <Y> 现在很明显,如果我试图根据模式验证文档,它会失败,因为 <X> <

    <A> <X> 随后是a <

    4 回复  |  直到 14 年前
        1
  •  4
  •   Dónal    8 年前

    我被同样的问题困扰了大约两周。 这可以通过使用JAXB编组/解组功能来实现。

    在JAXB编组/解组中,XML验证是一个可选功能。 因此,在创建Marshaller和UnMarshaller对象时,我们不调用setSchema(schema)方法。 省略此步骤可以避免封送/解组的XML验证功能。

    1. 如果一个元素在其他标记中放错了位置,那么在新的XML中就会省略它。编组/解组时不会抛出错误。

    public class JAXBSequenceUtil {
      public static void main(String[] args) throws JAXBException, IOException {
    
        String xml = FileUtils.readFileToString(new File(
                "./conf/out/Response_103_1015700001&^&IOF.xml"));
    
        System.out.println("Before marshalling : \n" + xml);
        String sequencedXml = correctSequence(xml,
                "org.acord.standards.life._2");
        System.out.println("After marshalling : \n" + sequencedXml);
      }
    
      /**
       * @param xml
       *            - XML string to be corrected for sequence.
       * @param jaxbPackage
       *            - package containing JAXB generated classes using XSD.
       * @return String - xml with corrected sequence
       * @throws JAXBException
       */
      public static String correctSequence(String xml, String jaxbPackage)
            throws JAXBException {
        JAXBContext jaxbContext = JAXBContext.newInstance(jaxbPackage);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        Object txLifeType = unmarshaller.unmarshal(new InputSource(
                new StringReader(xml)));
        System.out.println(txLifeType);
    
        StringWriter stringWriter = new StringWriter();
        Marshaller marshaller = jaxbContext.createMarshaller();
        marshaller.marshal(txLifeType, stringWriter);
    
        return stringWriter.toString();
      }
    }
    
        2
  •  3
  •   Pavel Minaev    16 年前

    <xs:element name="root">
      <xs:choice>
        <xs:sequence>
          <xs:element name="foo"/>
          <xs:element name="bar">
            <xs:element name="dee">
            <xs:element name="dum">
          </xs:element>
        </xs:sequence>
        <xs:sequence>
          <xs:element name="bar">
            <xs:element name="dum">
            <xs:element name="dee">
          </xs:element>
          <xs:element name="foo"/>
        </xs:sequence>
      </xs:choice>
    </xs:element>
    

    该输入XML:

    <root>
      <foo/>
      <bar>
        <dum/>
        <dee/>
      </bar>
    </root>
    

    这可以通过重新排序来符合模式 <foo> <bar> <dee> <dum> 似乎没有任何理由偏爱其中之一。

        3
  •  2
  •   Wim ten Brink    16 年前

    您可以使用XSOM读取XSD并生成将重新排序数据的样式表。然后使用该样式表转换XML。一旦XSOM为XSD生成了样式表,您就可以重复使用样式表,直到修改XSD或需要另一个XSD。


    因此,我将使用XSOM为XSD生成一个样式表,该样式表将逐节点复制XML,以便反复使用。样式表只需要在XSD发生变化时重写,并且它的执行速度将比Java API需要遍历节点本身时更快。样式表不关心顺序,所以它总是以正确的顺序结束。
    为了使其更有趣,您可以跳过XSOM,尝试使用读取XSD的样式表从中生成另一个样式表。生成的样式表将按照样式表中定义的确切顺序复制XML节点。这会很复杂吗?实际上,样式表需要为每个元素生成模板,并确保此元素中的子元素以正确的顺序处理。

    当我想到这一点时,我想知道以前是否已经这样做过。它将非常通用,能够处理几乎所有的XSD/XML。

    独特的

        4
  •  1
  •   Timothy Walters    16 年前

    //假设第一个调用是SortChildrenIntoNewDocument(sourceDom.DocumentElement、targetDom.DocumentElement、schema.RootElement)

    public void SortChildrenIntoNewDocument( XmlElement source, XmlElement target, SchemaElement schemaElement )
    {
        // whatever method you use to ask the XSOM to tell you the correct contents
        SchemaElement[] orderedChildren = schemaElement.GetChildren();
        for( int i = 0; i < orderedChildren.Length; i++ )
        {
            XmlElement sourceChild = source.SelectChildByName( orderedChildren[ i ].Name );
            XmlElement targetChild = target.AddChild( sourceChild )
            // recursive-call
            SortChildrenIntoNewDocument( sourceChild, targetChild, orderedChildren[ i ] );
        }
    }
    

    如果它是一棵深树,我不建议使用递归方法,在这种情况下,你必须创建一些“树行者”类型的对象。这种方法的优点是,你可以处理更复杂的事情,比如当模式说你可以有0个或更多的元素时,你可以继续处理源节点,直到没有更多的匹配,然后从那里继续移动模式漫游器。

    推荐文章