【问题标题】:Split the xml into smaller one based on change in tag values根据标签值的变化将 xml 拆分为较小的
【发布时间】:2018-10-01 11:05:56
【问题描述】:
<?xml version="1.0" encoding="UTF-16"?>
<ABC>
    <END />
    <Tables>
        <START>
            <row>
                <id>111</id>
                <name>abc</name>
                <deptId>1</deptId>
            </row>
            <row>
                <id>112</id>
                <name>abc1</name>
                <deptId>1</deptId>
            </row>
            <row>
                <id>113</id>
                <name>abc3</name>
                <deptId>1</deptId>
            </row>
            <row>
                <id>222</id>
                <name>def</name>
                <deptId>2</deptId>
            </row>
            <row>
                <id>333</id>
                <name>pqr</name>
                <deptId>2</deptId>
            </row>
            <row>
                <id>444</id>
                <name>xyz</name>
                <deptId>2</deptId>
            </row>
            <row>
                <id>555</id>
                <name>lmn</name>
                <deptId>3</deptId>
            </row>
            <row>
                <id>555</id>
                <name>lmn</name>
                <deptId>3</deptId>
            </row>
        </START>
    </Tables>
</ABC>

我有一个具有上述结构的 xml。我必须根据不同的deptId 将 xml 溢出到 3 个 xml。 我必须根据标签值的变化将 xml 拆分为更小的一个。我的元素是deptId,它的值在一些行之后发生了变化。 所有具有相同deptId 的元素都在一个序列中。

所需的输出是: 将 xml 名称作为部门 id 很好。

第一个xml名称为1.xml

<?xml version="1.0" encoding="UTF-16"?>
<ABC>
    <END />
    <Tables>
        <START>
            <row>
                <id>111</id>
                <name>abc</name>
                <deptId>1</deptId>
            </row>
            <row>
                <id>112</id>
                <name>abc1</name>
                <deptId>1</deptId>
            </row>
            <row>
                <id>113</id>
                <name>abc3</name>
                <deptId>1</deptId>
            </row>
        </START>
    </Tables>
</ABC>

名为 2.xml 的第二个 xml:

<?xml version="1.0" encoding="UTF-16"?>
<ABC>
    <END />
    <Tables>
        <START>
            <row>
                <id>222</id>
                <name>def</name>
                <deptId>2</deptId>
            </row>
            <row>
                <id>333</id>
                <name>pqr</name>
                <deptId>2</deptId>
            </row>
            <row>
                <id>444</id>
                <name>xyz</name>
                <deptId>2</deptId>
            </row>
        </START>
    </Tables>
</ABC>

第三个名为 3.xml 的 xml:

<?xml version="1.0" encoding="UTF-16"?>
<ABC>
    <END />
    <Tables>
        <START>
            <row>
                <id>113</id>
                <name>abc3</name>
                <deptId>1</deptId>
            </row>
        </START>
    </Tables>
</ABC>

我通过引用几个选项来尝试使用 StAXSource 选项 我尝试过的选项是参考以下链接

Split xml Split large xml

这是已经尝试过的示例代码。

import java.io.File;
import java.io.FileReader;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamResult;

public class Demo2 {

public static void main(String[] args) throws Exception {
    XMLInputFactory xif = XMLInputFactory.newInstance();
    XMLStreamReader streamReader = xif.createXMLStreamReader(new FileReader("D://SmallXmltoSplit.xml"));

    streamReader.nextTag(); // Advance to next element
    streamReader.nextTag();
    streamReader.nextTag();
    streamReader.nextTag();
    streamReader.nextTag();
    streamReader.nextTag();

    TransformerFactory tf = TransformerFactory.newInstance();
    Transformer t = tf.newTransformer();
    String deptId = null;
    File file = new File("D://test" + ".xml");
    while (streamReader.hasNext()) {
        if (streamReader.isStartElement()) {
            if (streamReader.getLocalName().equals("deptId")) {
                if (deptId == null) {
                    deptId = streamReader.getElementText();
                    file = new File("D://" + deptId + ".xml");
                    t.transform(new StAXSource(streamReader), new StreamResult(file));
                } else if (deptId != streamReader.getElementText()) {
                    file = new File("D://" + deptId + ".xml");
                    t.transform(new StAXSource(streamReader), new StreamResult(file));
                } 
            }
            t.transform(new StAXSource(streamReader), new StreamResult(file));
        }
        streamReader.next();
    }
}

}

【问题讨论】:

    标签: java xml xml-parsing xslt-2.0 stax


    【解决方案1】:

    使用 XSLT 2.0 更容易做到这一点:

    <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform version="2.0">
      <xsl:template match="/">
        <xsl:for-each-group select="//row" group-adjacent="deptId">
          <xsl:result-document href="{current-grouping-key()}.xml">
            <ABC>
             <END />
              <Tables>
               <START>
                <xsl:copy-of select="current-group()"/>
               </START>
              </Tables>
            </ABC>
          </xsl:result-document>
        </xsl:for-each-group>
      </xsl:template>
    </xsl:transform>
    

    要从 Java 应用程序运行它,您需要下载 Saxon,然后使用以下逻辑调用它:

        Processor proc = new Processor(false);
        XsltCompiler comp = proc.newXsltCompiler();
        XsltExecutable exp = comp.compile(new StreamSource(new File("my-stylesheet.xsl")));
        Serializer out = proc.newSerializer(new File("output.xml"));
        Xslt30Transformer trans = exp.load30();
        trans.applyTemplates(new StreamSource(new File("input.xml"), out);
    

    更多详情:http://www.saxonica.com/documentation/index.html#!using-xsl/embedding/s9api-transformation

    【讨论】:

    • 您能指导我如何执行相同的操作吗?
    • 我已添加到我的答案中。
    【解决方案2】:

    XML 读取应该通过&lt;row&gt;,或多或少如下:

        XMLInputFactory xif = XMLInputFactory.newInstance();
        // Do not use a Reader, especially not a FileReader. An InputStream leaves the
        // encoding of the XML to the XMLStreamReader.
        InputStream in = Files.newInputStream(Paths.get("D:/SmallXmltoSplit.xml"));
        XMLStreamReader streamReader = xif.createXMLStreamReader(in);
        streamReader.nextTag();
    
        String id = "";
        String name = "";
        String deptId = "";
    
        String oldDeptId = null;
    

    // 文件file = new File("D:/test" + ".xml");

        while (streamReader.hasNext()) {
            if (streamReader.isStartElement()) {
                switch (streamReader.getLocalName()) {
                case "row":
                    id = "";
                    name = "";
                    deptId = "";
                    break;
                case "id":
                    id = streamReader.getElementText();
                    break;
                case "name":
                    name = streamReader.getElementText();
                    break;
                case "deptId":
                    deptId = streamReader.getElementText();
                    break;
                }
            }
            if (streamReader.isEndElement()) {
                switch (streamReader.getLocalName()) {
                case "START":
                    if (oldDeptId != null) {
                        saveDept();
                        //oldDeptId = deptId;
                    }
                    break;
                case "row":
                    if (!deptId.equals(oldDeptId)) {
                        if (oldDeptId != null) {
                            saveDept();
                            oldDeptId = deptId;
                        }
                        startDept(deptId);
                    }
                    appendDeptRow(id, name, deptId);
                    break;
                }
            }
        }
    

    无需转换即可写作;事实上它可以作为文本来完成。

    我把它留作练习。

    不应使用 FileReader 和 FileWriter,因为它们使用默认平台编码对字节进行编码。 Files 类有很多不错的文件函数。

    这里的另一个特点是 UTF-16 编码,它使几乎 ASCII 文件的大小翻了一番。正如您提到的有一个大文件,最好将该文件保存为 UTF-8,即使名称是波斯语、希腊语、日语或保加利亚语。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-09
      • 2013-08-31
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      • 2015-09-26
      • 1970-01-01
      相关资源
      最近更新 更多