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

如何扩充多个XML子元素Camel?

  •  0
  • Screwtape  · 技术社区  · 6 年前

    我有一个用例,我需要从一个数据库中获取一个现有的XML文档,并将其扩充到一个集成过程中。

    <parent>
      <child>
        <data>A</data>
      </child>
      <child>
        <data>B</data>
      </child>
      <parentData>
        <data/>
      </parentData>
    </parent>
    

    我要做的是添加一个 <moreData .../> 树到每个 child

    我可以编写一个定制的bean来完成所有的工作,但是这感觉不是正确的方法。我考虑过使用一个基于xpath for child的拆分器,然后是一个内容丰富器,这将允许我获取额外的数据,但我看不到如何在之后重新组合所有内容。

    目前,我认为我需要使用一个循环,但这也让人觉得很笨拙,需要为内容丰富器定制一个聚合策略。

    from("direct:a")
      .loop().xpath("count( parent/child )", Integer.class )
      .setHeader("Key")
      .xpath( "parent/child[function:properties('CamelLoopIndex')]/data", String.class )
      .enrich("sql:SELECT xmldata FROM dataTable WHERE key = :#Key?dataSource=myDS",
         new MyCustomAggregationStrategy() )
    

    这肯定是骆驼世界里每天都会发生的事,但我找不到任何例子来说明如何做到这一点。

    如果我在一个自定义bean中执行此操作,我将得到 元素,然后遍历执行查询的节点集,并将结果作为新的子节点附加到节点。我就是不知道怎么在骆驼身上做到这一点。

    任何想法或暗示都会很好!谢谢!

    1 回复  |  直到 6 年前
        1
  •  1
  •   c0ld    6 年前

    您可以尝试准备新节点的映射,然后使用xslt转换父xml,并在xsl中使用java获得准备好的新节点。这里有一些例子。路线:

     @Override
    public void configure() throws Exception {
    from("timer://foo?period=30s")
                .setBody(constant("<parent>\n" +
                        "  <child>\n" +
                        "    <data>A</data>\n" +
                        "  </child>\n" +
                        "  <child>\n" +
                        "    <data>B</data>\n" +
                        "  </child>\n" +
                        "  <parentData>\n" +
                        "    <data/>\n" +
                        "  </parentData>\n" +
                        "</parent>"))
                .convertBodyTo(org.w3c.dom.Document.class)
                .setProperty("oldBody", simple("body"))
    
                .split(xpath("//child"), (oldExchange, newExchange) -> {
                    Map<String, String> map = oldExchange != null ? oldExchange.getProperty("map", Map.class) : new HashMap<>();
                    map.put(newExchange.getIn().getHeader("Key", String.class), newExchange.getIn().getBody(String.class));
                    newExchange.setProperty("map", map);
                    return newExchange;
                })
                .setHeader("Key", xpath("//data/text()"))
    //                .to("sql:SELECT xmldata FROM dataTable WHERE key = :#Key?dataSource=#myDS")
                //emulate result of your sql
                .process(exchange -> {
                    exchange.getIn().setBody("<someNewData>".concat(exchange.getIn().getHeader("Key", String.class).concat("Result")).concat("</someNewData>"));
                })
                .end()
                .setBody(exchangeProperty("oldBody"))
                .to("xslt:xslt/result.xsl?transformerFactory=#nsTF")
                .log(LoggingLevel.INFO, "Body:${body}");}
    
    public static String getElement(Object map, String key) {
        return (String) ((Map) map).get(key);
    }
    

    nsTF是类bean:

    public class NonSecureTransfomerFactory extends TransformerFactoryImpl {
    @Override
    //for using java inside xsl
    public boolean isSecureProcessing()
    {
        return false;
    }
    }
    

    xslt样式表:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:getter="my.package.RouteHelper">
    <xsl:output method="xml" version="1.0" encoding="UTF-8"/>
    <xsl:strip-space elements='*'/>
    
    <xsl:param name="map"/>
    
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="child">
        <xsl:copy>
            <xsl:variable name="key" select="data/text()"/>
            <xsl:value-of disable-output-escaping="yes"     select="getter:getElement($map,$key)"/>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    

    <parent>
    <child>
        <someNewData>AResult</someNewData>
        <data>A</data>
    </child>
    <child>
        <someNewData>BResult</someNewData>
        <data>B</data>
    </child>
    <parentData>
        <data/>
    </parentData>
    </parent>