如何为两个边界元素之间的元素创建新的XML父元素?

huangapple go评论78阅读模式
英文:

How can i create a new XML parents for elements which are between two boundary elements

问题

我想在JDOM2结构中的两个边界元素之间创建一个新的XML父元素,尽可能高的级别。
实际上,对于<start><stop>元素的放置没有限制。

简化示例:

<root>
    <a>
        <ax>
            <start></start>
        </ax>
        <ay></ay>
        <az></az>
    </a>
    <b>
       <bx></bx>
    </b>
    <c>
        <cx></cx>
        <cy></cy>
        <cz>
            <cza></cza>
            <czb>
                <stop></stop>
            </czb>
        </cz>
    </c>
</code>

输出:

```xml
&lt;root&gt;
    &lt;a&gt;
        &lt;ax&gt;
            &lt;start&gt;&lt;/start&gt;
        &lt;/ax&gt;
        &lt;added&gt;
            &lt;ay&gt;&lt;/ay&gt;
            &lt;az&gt;&lt;/az&gt;
        &lt;/added&gt;
    &lt;/a&gt;
    &lt;added&gt;
        &lt;b&gt;
            &lt;bx&gt;&lt;/bx&gt;
        &lt;/b&gt;
    &lt;/added&gt;
    &lt;c&gt;
        &lt;added&gt;
            &lt;cx&gt;&lt;/cx&gt;
            &lt;cy&gt;&lt;/cy&gt;
        &lt;/added&gt;
        &lt;cz&gt;
            &lt;added&gt;
                &lt;cza&gt;&lt;/cza&gt;
            &lt;/added&gt;
            &lt;czb&gt;
                &lt;stop&gt;&lt;/stop&gt;
            &lt;/czb&gt;
        &lt;/cz&gt;
    &lt;/c&gt;
</code>
英文:

I would like to create a new XML parents at the highest possible levels for elements which are between two boundary elements in the JDOM2 structure.
Practically there are no limitations to the placement of the &lt;start&gt; and &lt;stop&gt; elements.

Simplified example:

&lt;root&gt;
    &lt;a&gt;
        &lt;ax&gt;
            &lt;start&gt;&lt;/start&gt;
        &lt;/ax&gt;
        &lt;ay&gt;&lt;/ay&gt;
        &lt;az&gt;&lt;/az&gt;
    &lt;/a&gt;
    &lt;b&gt;
       &lt;bx&gt;&lt;/bx&gt;
    &lt;/b&gt;
    &lt;c&gt;
        &lt;cx&gt;&lt;/cx&gt;
        &lt;cy&gt;&lt;/cy&gt;
        &lt;cz&gt;
            &lt;cza&gt;&lt;/cza&gt;
            &lt;czb&gt;
                &lt;stop&gt;&lt;/stop&gt;
            &lt;/czb&gt;
        &lt;/cz&gt;
    &lt;/c&gt;

output:

&lt;root&gt;
    &lt;a&gt;
        &lt;ax&gt;
            &lt;start&gt;&lt;/start&gt;
        &lt;/ax&gt;
        &lt;added&gt;
            &lt;ay&gt;&lt;/ay&gt;
            &lt;az&gt;&lt;/az&gt;
        &lt;/added&gt;
    &lt;/a&gt;
    &lt;added&gt;
        &lt;b&gt;
            &lt;bx&gt;&lt;/bx&gt;
        &lt;/b&gt;
    &lt;/added&gt;
    &lt;c&gt;
        &lt;added&gt;
            &lt;cx&gt;&lt;/cx&gt;
            &lt;cy&gt;&lt;/cy&gt;
        &lt;/added&gt;
        &lt;cz&gt;
            &lt;added&gt;
                &lt;cza&gt;&lt;/cza&gt;
            &lt;/added&gt;
            &lt;czb&gt;
                &lt;stop&gt;&lt;/stop&gt;
            &lt;/czb&gt;
        &lt;/cz&gt;
    &lt;/c&gt;

答案1

得分: 1

以下是一些关于使用XQuery 3.1的尝试,用于识别和包装元素的示例代码。您可以在Java中使用Saxon HE或BaseX运行它,但不确定对于JDOM的哪个库可以使用,我认为Saxon支持它。示例代码如下:

declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";

declare option output:method 'xml';
declare option output:indent 'yes';

declare function local:transform($node as node(), $siblings-to-be-wrapped as array(element()*)*) {
  typeswitch ($node)
    case document-node()
      return document { $node!node()!local:transform(., $siblings-to-be-wrapped) }
    case element()
      return 
        let $match := $siblings-to-be-wrapped[some $el in ?* satisfies $el is $node]
        return if ($node is $match?1)
               then <added>{$match}</added>
               else if (not(exists($match)))
               then element { node-name($node) } { $node!@*, $node!node()!local:transform(., $siblings-to-be-wrapped) }
               else ()
    default
      return $node
};

let $start-elements := //start,
    $stop-elements := //stop,
    $siblings-to-be-wrapped := for-each-pair(
      $start-elements, 
      $stop-elements, 
      function($s, $e) { 
        let $elements-to-be-wrapped := outermost(root($s)//*[. >> $s and . << $e][not(some $d in .//* satisfies ($d is $s or $d is $e))])
        for tumbling window $siblings in $elements-to-be-wrapped
        start $s when true()
        end next $n when not($s/.. is $n/..)
        return array { $siblings }
      }
    )
return
    local:transform(/, $siblings-to-be-wrapped)

这段代码的作用是识别特定的起始元素和停止元素之间的元素,并将它们包装在元素中。请注意,这段代码假设您的XML文档中只包含要包装的元素节点,不包含混合内容或文本节点。

如果您要在Saxon HE中运行这个XQuery代码,可以使用下面的Java代码:

import net.sf.saxon.s9api.*;

import java.io.File;
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException, SaxonApiException {
        Processor processor = new Processor();

        DocumentBuilder docBuilder = processor.newDocumentBuilder();

        XdmNode inputDoc = docBuilder.build(new File("sample1.xml"));

        XQueryCompiler xqueryCompiler = processor.newXQueryCompiler();

        XQueryExecutable xqueryExecutable = xqueryCompiler.compile(new File("wrap-siblings-between-milestones1.xq"));

        XQueryEvaluator xqueryEvaluator = xqueryExecutable.load();

        xqueryEvaluator.setContextItem(inputDoc);

        xqueryEvaluator.run(processor.newSerializer(System.out));
    }
}

这个Java代码用于加载XML文档并运行XQuery代码,将结果输出到System.out。

如果您要在Saxon HE中使用JDOM2,您需要下载源代码并将net.sf.saxon.option.jdom2包编译到您的Java项目中。然后,您可以使用以下Java代码来运行XQuery代码并返回新的JDOM文档:

import net.sf.saxon.option.jdom2.JDOM2ObjectModel;
import net.sf.saxon.s9api.*;
import org.jdom2.Document;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import org.jdom2.transform.JDOMResult;

import java.io.File;
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException, SaxonApiException, JDOMException {
        Processor processor = new Processor();

        processor.getUnderlyingConfiguration().registerExternalObjectModel(new JDOM2ObjectModel());

        Document jdomDocument = new SAXBuilder().build(new File("sample1.xml"));

        DocumentBuilder docBuilder = processor.newDocumentBuilder();

        XdmNode inputDoc = docBuilder.wrap(jdomDocument);

        XQueryCompiler xqueryCompiler = processor.newXQueryCompiler();

        XQueryExecutable xqueryExecutable = xqueryCompiler.compile(new File("wrap-siblings-between-milestones1.xq"));

        XQueryEvaluator xqueryEvaluator = xqueryExecutable.load();

        xqueryEvaluator.setContextItem(inputDoc);

        JDOMResult jdomResult = new JDOMResult();

        xqueryEvaluator.run(new SAXDestination(jdomResult.getHandler()));

        Document resultDoc = jdomResult.getDocument();

        XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat());

        xmlOutputter.output(resultDoc, System.out);

    }
}

这个Java代码用于加载JDOM文档并运行XQuery代码,然后将结果输出到System.out。希望这些信息对您有所帮助。

英文:

Here is some attempt in XQuery 3.1 (which you can run with Java using Saxon HE or BaseX, not sure whether for both over JDOM, I think Saxon supports that https://www.saxonica.com/html/documentation11/sourcedocs/tree-models/thirdparty.html) to identify and wrap the elements e.g.

declare namespace output = &quot;http://www.w3.org/2010/xslt-xquery-serialization&quot;;

declare option output:method &#39;xml&#39;;
declare option output:indent &#39;yes&#39;;

declare function local:transform($node as node(), $siblings-to-be-wrapped as array(element()*)*) {
  typeswitch ($node)
    case document-node()
      return document { $node!node()!local:transform(., $siblings-to-be-wrapped) }
    case element()
      return 
        let $match := $siblings-to-be-wrapped[some $el in ?* satisfies $el is $node]
        return if ($node is $match?1)
               then &lt;added&gt;{$match}&lt;/added&gt;
               else if (not(exists($match)))
               then element { node-name($node) } { $node!@*, $node!node()!local:transform(., $siblings-to-be-wrapped) }
               else ()
    default
      return $node
};

let $start-elements := //start,
    $stop-elements := //stop,
    $siblings-to-be-wrapped := for-each-pair(
      $start-elements, 
      $stop-elements, 
      function($s, $e) { 
        let $elements-to-be-wrapped := outermost(root($s)//*[. &gt;&gt; $s and . &lt;&lt; $e][not(some $d in .//* satisfies ($d is $s or $d is $e))])
        for tumbling window $siblings in $elements-to-be-wrapped
        start $s when true()
        end next $n when not($s/.. is $n/..)
        return array { $siblings }
      }
    )
return
    local:transform(/, $siblings-to-be-wrapped)

Result is e.g.

&lt;root&gt;
   &lt;a&gt;
      &lt;ax&gt;
         &lt;start/&gt;
      &lt;/ax&gt;
      &lt;added&gt;
         &lt;ay/&gt;
         &lt;az/&gt;
      &lt;/added&gt;
   &lt;/a&gt;
   &lt;added&gt;
      &lt;b&gt;
         &lt;bx/&gt;
      &lt;/b&gt;
   &lt;/added&gt;
   &lt;c&gt;
      &lt;added&gt;
         &lt;cx/&gt;
         &lt;cy/&gt;
      &lt;/added&gt;
      &lt;cz&gt;
         &lt;added&gt;
            &lt;cza/&gt;
         &lt;/added&gt;
         &lt;czb&gt;
            &lt;stop/&gt;
         &lt;/czb&gt;
      &lt;/cz&gt;
   &lt;/c&gt;
&lt;/root&gt;

Not well tested and currently, like in the shown input sample, looking only for element nodes to be wrapped, not expecting mixed contents with text nodes split by e.g. &lt;start/&gt; and &lt;stop/&gt;.

Minimal Saxon HE (used 12.3) code to run XQuery against an input file and output the result (for testing to System.out) is e.g.

import net.sf.saxon.s9api.*;

import java.io.File;
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException, SaxonApiException {
        Processor processor = new Processor();

        DocumentBuilder docBuilder = processor.newDocumentBuilder();

        XdmNode inputDoc = docBuilder.build(new File(&quot;sample1.xml&quot;));

        XQueryCompiler xqueryCompiler = processor.newXQueryCompiler();

        XQueryExecutable xqueryExecutable = xqueryCompiler.compile(new File(&quot;wrap-siblings-between-milestones1.xq&quot;));

        XQueryEvaluator xqueryEvaluator = xqueryExecutable.load();

        xqueryEvaluator.setContextItem(inputDoc);

        xqueryEvaluator.run(processor.newSerializer(System.out));
    }
}

Example online: https://github.com/martin-honnen/SaxonXQueryWrapSiblingsBetweenMileStones

To use JDOM2 with Saxon HE you need to download the source from https://github.com/Saxonica/Saxon-HE/tree/main/12/source and compile the net.sf.saxon.option.jdom2 package into your Java project (and it seems comment out line 50 in JDOM2DocumentWrapper.java before you do that), then the code to run XQuery on the JDOM Document and return a new one is e.g.

import net.sf.saxon.option.jdom2.JDOM2ObjectModel;
import net.sf.saxon.s9api.*;
import org.jdom2.Document;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import org.jdom2.transform.JDOMResult;

import java.io.File;
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException, SaxonApiException, JDOMException {
        Processor processor = new Processor();

        processor.getUnderlyingConfiguration().registerExternalObjectModel(new JDOM2ObjectModel());

        Document jdomDocument = new SAXBuilder().build(new File(&quot;sample1.xml&quot;));

        DocumentBuilder docBuilder = processor.newDocumentBuilder();

        XdmNode inputDoc = docBuilder.wrap(jdomDocument);

        XQueryCompiler xqueryCompiler = processor.newXQueryCompiler();

        XQueryExecutable xqueryExecutable = xqueryCompiler.compile(new File(&quot;wrap-siblings-between-milestones1.xq&quot;));

        XQueryEvaluator xqueryEvaluator = xqueryExecutable.load();

        xqueryEvaluator.setContextItem(inputDoc);

        JDOMResult jdomResult = new JDOMResult();

        xqueryEvaluator.run(new SAXDestination(jdomResult.getHandler()));

        Document resultDoc = jdomResult.getDocument();

        XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat());

        xmlOutputter.output(resultDoc, System.out);

    }
}

Example online: https://github.com/martin-honnen/SaxonXQueryWrapSiblingsBetweenMileStones/tree/UseJDOM

huangapple
  • 本文由 发表于 2023年7月14日 02:42:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/76682383.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定