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

将不匹配的数据模型从XML转换为JSON的最佳实践

  •  1
  • tgr  · 技术社区  · 7 年前

    问题

    我的任务是通过第三方API集成外部系统。我收到的数据是具有给定结构的XML文件,而API需要具有不同结构的JSON。解析和生成这两者本身都不是问题,但转换此类数据的最佳实践是什么。我已经在下面列出了我能想到的解决方案。

    解决方案1

    我想到的第一个解决方案是分别创建两个模型并创建一个转换器。这样,映射问题就少了。然而,我必须重新创建和维护一个已经存在的域模型。重用是没有选择的,因为这个域模型已经有二十年的历史了,并且不能与业务逻辑分离。此外,我觉得我违反了 SOC principle ,因为转换器需要了解模型的结构。

    解决方案2

    或者,我可以创建一个模型,并使用JAXB和Jackson注释对其进行注释。这种方法提供了一个单一的模型,而不需要转换器。这减少了对这些类的维护。另一方面,这可能会产生更多的粘合代码来弥补两个模型之间的结构差异。


    我对这两种解决方案都不感兴趣。但如果必须的话,我愿意接受一个作为我的命运。如果有任何其他方法来解决这个问题,我将非常感谢了解它。高度赞赏任何一种方法的示例来源。

    3 回复  |  直到 4 年前
        1
  •  2
  •   lexicore    7 年前

    解决方案2 绝对更有吸引力。但问题是,您说XML和JSON有不同的结构。如果存在结构性差异,则必须对其进行补偿。我不确定单一模式如何可能,必须以某种方式进行补偿。

    因此,关键是您需要某种灵活的方法来映射不同的结构。XSLT是一种很好的工具。所以我建议一个不同的解决方案。

    只创建一个与JSON匹配的模型,用Jackson注释(或任何JSON使用的注释)对其进行注释。还可以使用JAXB注释对其进行注释。到目前为止,它就像解决方案2。然而,问题是,本例中的XML结构基于JSON结构,与传入的XML结构不直接兼容。要解决这个问题,请编写一个XSLT转换,将传入的XML转换为基于JSON的XML结构。基本上:

    XML (incoming)  
      -(XSLT)-> XML (JSON-based)
      -(JAXB)-> Java objects
      -(Jackson)->
    JSON
    

    XSLT是非常强大和灵活的XML转换工具。一个重要的反面是,您可能需要两个XSLT:正向和反向。否则,测试将相当困难。

    我见过几次的另一种选择是,实际上有两个模型,并使用类似于推土机的东西在它们之间进行转换:

    XML (incoming)  
      -(JAXB)-> Java objects (incoming XML model)
      -(Dozer)-> Java object (JSON-based model)
      -(Jackson)->
    JSON
    

    这也可能有效。您应该为传入的XML创建一个XML模式,这样就可以为传入的XML模型生成Java类,这样您就不会有太多的维护开销。问题是(至少在我看来)Dozer和诸如此类的工具没有XSLT灵活和强大。我认为编写XSLT在XML结构之间转换要比使用Dozer在Java结构之间转换容易得多。

        2
  •  1
  •   Pylot    7 年前

    XSLT为这种需求提供了一个优雅的解决方案。作为一个示例,下面是一个示例转换,它适用于上提供的XML this page 并将其转换为同一页面上给定的json。

    <?xml version="1.0" encoding="utf-8"?>    
    <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
        <xsl:output method="text" />
        <xsl:strip-space elements="*" />
        <xsl:variable name="nl"><xsl:text>&#xa;</xsl:text></xsl:variable>
        <xsl:variable name="q">"</xsl:variable>
        <xsl:variable name="bInd" select="'  '" />
    
        <xsl:template match="glossary">
            <xsl:value-of select="concat('{', $nl, $bInd, $q, local-name(.), $q, ' : {')" />
    
            <xsl:apply-templates>
                <xsl:with-param name="ind" select="concat($bInd, $bInd)" />
            </xsl:apply-templates>
    
            <xsl:value-of select="concat($nl, $bInd, '}', $nl, '}', $nl)" />
        </xsl:template>
    
        <xsl:template match="title">
            <xsl:param name="ind" />
            <xsl:value-of select="concat($nl, $ind, '  ', $q, local-name(.), $q, ' : ', $q, ., $q)" />
        </xsl:template>
    
        <!-- Other text elements -->
        <xsl:template match="*">
            <xsl:param name="ind" />
            <xsl:value-of select="concat($nl, $ind, ', ', $q, local-name(.), $q, ' : ', $q, ., $q)" />
        </xsl:template>
    
        <xsl:template match="GlossEntry">
            <xsl:param name="ind" />
            <xsl:value-of select="concat($nl, $ind, $q, local-name(.), $q, ' : {')" />
            <xsl:value-of select="concat($nl, $ind, $bInd, '  ',$q, 'ID', $q, ' : ', $q, @ID , $q)" />
            <xsl:value-of select="concat($nl, $ind, $bInd, ', ', $q, 'SortAs', $q, ' : ', $q, @SortAs , $q)" />
    
            <xsl:apply-templates>
                <xsl:with-param name="ind" select="concat($ind, $bInd)" />
            </xsl:apply-templates>
    
            <xsl:value-of select="concat($nl, $ind, '}')" />
        </xsl:template>
    
        <xsl:template match="GlossDef">
            <xsl:param name="ind" />
            <xsl:value-of select="concat($nl, $ind, ', ', $q, local-name(.), $q, ' : {')" />
            <xsl:value-of select="concat($nl, $ind, $bInd, '  ', $q, 'para', $q, ' : ', $q, para, $q)" />
            <xsl:value-of select="concat($nl, $ind, $bInd, ', ', $q, 'GlossSeeAlso', $q, ' : [ ')" />
    
            <xsl:for-each select="GlossSeeAlso">
                <xsl:apply-templates select=".">
                    <xsl:with-param name="pos" select="position()" />
                </xsl:apply-templates>
            </xsl:for-each>
    
            <xsl:value-of select="' ]'" />
            <xsl:value-of select="concat($nl, $ind, '}')" />
        </xsl:template>
    
        <xsl:template match="GlossSeeAlso">
            <xsl:param name="pos" />
    
            <xsl:if test="$pos > 1">
                <xsl:value-of select="', '" />
            </xsl:if>
    
            <xsl:value-of select="concat($q, @OtherTerm, $q)" />
        </xsl:template>
    
        <xsl:template match="GlossSee">
            <xsl:param name="ind" />
            <xsl:value-of select="concat($nl, $ind, ', ', $q, local-name(.), $q, ' : ', $q, @OtherTerm, $q)" />
        </xsl:template>
    
        <xsl:template match="GlossDiv | GlossList">
            <xsl:param name="ind" />
            <xsl:value-of select="concat($nl, $ind, ', ', $q, local-name(.), $q, ' : {')" />
    
            <xsl:apply-templates>
                <xsl:with-param name="ind" select="concat($ind, $bInd)" />
            </xsl:apply-templates>
    
            <xsl:value-of select="concat($nl, $ind, '}')" />
        </xsl:template>
    </xsl:transform>
    

    此示例转换为XSLT 1.0。您可以通过在XML文件中添加对它的引用,并在web浏览器中加载XML文件来测试它。

    例如,如果上述变换存储在测试中。xsl,将XML置于测试中。xml,其转换引用如下:

    <?xml version="1.0" encoding="utf-8"?>
    <?xml-stylesheet type="text/xsl" href="test.xsl"?>
    
    <glossary>
        <title>example glossary</title>
    
        <GlossDiv>
            <title>S</title>
    
            <GlossList>
                <GlossEntry ID="SGML" SortAs="SGML">
                    <GlossTerm>Standard Generalized Markup Language</GlossTerm>
                    <Acronym>SGML</Acronym>
                    <Abbrev>ISO 8879:1986</Abbrev>
    
                    <GlossDef>
                        <para>A meta-markup language, used to create markup languages such as DocBook.</para>
                        <GlossSeeAlso OtherTerm="GML" />
                        <GlossSeeAlso OtherTerm="XML" />
                    </GlossDef>
    
                    <GlossSee OtherTerm="markup" />
                </GlossEntry>
            </GlossList>
        </GlossDiv>
    </glossary>
    
        3
  •  -1
  •   Ramesh Fadatare    7 年前

    我的建议是,您可以为xml结构创建模型,并将模型转换为json。有第三方JAR将模型转换为json,反之亦然。

    同时签出此链接- Quickest way to convert XML to JSON in Java