将xml转换为另一个xml的最简单方法是什么?

时间:2014-05-12 14:53:30

标签: java xml xslt transformation

我有一个 xml 文档,如下所示:

<document>
  <primitive name="password" type="xs:string" path="" mandatory="false" />
  <structure name="username" mandatory="true">
    <primitive name="first-name" type="xs:string" path="" mandatory="true" />
    <primitive name="last-name" type="xs:string" path="" mandatory="true" />
  </structure>
  <list name="addresses" path="" mandatory="true">
    <structure name="address" mandatory="true">
      <primitive name="country" type="xs:string" path="" mandatory="true" default-value="HU"/>
      <primitive name="po-box" type="xs:string" path="" mandatory="true" />
    </structure>
  </list>
  <list name="owned-phones" path="" mandatory="true">
    <structure name="phone" mandatory="true">
      <primitive name="number" type="xs:int" path="" mandatory="true" />
      <primitive name="device-name" type="xs:string" path="" mandatory="true" />
      <list name="similar-devices" path="" mandatory="true">
        <structure name="device" mandatory="true">
          <primitive name="device-name" type="xs:string" path="" mandatory="true" />
        </structure>
      </list>
    </structure>
  </list>
  <list name="aliases" path="" mandatory="true">
    <primitive name="alias" type="xs:string" path="" mandatory="true" />
  </list>
  <template name="tou">
    <![CDATA[
      wombat
    ]]>
  </template>

这描述了数据结构的规则,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<document>
  <password>ajshakjsdh</password>
  <username>
    <first-name>Kevin</first-name>
    <last-name>Smith</last-name>
  </username>

  <addresses>
    <address>
      <country>HU</country>
      <po-box>12234</po-box>
    </address>
    <address>
      <country>US</country>
      <po-box>666</po-box>
    </address>
  </addresses>

  <owned-phones>
    <phone>
      <number>2431241</number>
      <device-name>Nokia</device-name>
      <similar-devices>
        <device>
          <device-name>Windozfon</device-name>
        </device>
      </similar-devices>
    </phone>
    <phone>
      <number>68741</number>
      <device-name>Samsung</device-name>
      <similar-devices>
        <device>
          <device-name>Android</device-name>
        </device>
        <device>
          <device-name>Blackberry</device-name>
        </device>
      </similar-devices>
    </phone>
  </owned-phones>

  <aliases>
    <alias>Alias1</alias>
    <alias>Alias2</alias>
  </aliases>
  <!-- tou is missing but not mandatory -->
</document>

我有一组转换规则,可用于将第一个 xml 文件转换为 xsd 文档,该文档可用于验证数据结构(第二个代码)块):

<primitive name="$primitive_name" type="$primitive_type" mandatory="$primitive_mandatory" />

转换为

<xs:element name="$primitive_name" type="$primitive_type" minOccurs="$primitive_mandatory ? 1 : 0" maxOccurs="1" />


<structure name="$structure_name" mandatory="$structure_mandatory">
<!-- anything inside recursively transformed -->
</structure>

转换为

<xs:element name="$structure_name" minOccurs="$structure_mandatory ? 1 : 0" maxOccurs="1">
  <xs:complexType>
    <xs:all>
      <!-- anything inside recursively transformed -->
    </xs:all>
  </xs:complexType>
</xs:element>


<list name="$list_name" mandatory="$list_mandatory">
    <!-- anything inside recursively transformed -->
</list>

转换为

<xs:element name="$list_name" minOccurs="$list_mandatory ? 1 : 0">
  <xs:complexType>
    <xs:sequence maxOccurs="unbounded">
    <!-- anything inside recursively transformed --> 
    </xs:sequence>
  </xs:complexType>
</xs:element>

我的问题是我应该使用什么工具进行这些简单的转换?我听说 XSLT 是这里的方法。我做了一些关于它的研究,这对我来说似乎有些过分。至少我无法在 XSLT 中找到正确的转换规则。你能提供一些指示我应该从哪里开始吗?

2 个答案:

答案 0 :(得分:3)

XSLT非常适合您的问题。您可以轻松地将结构映射到将以递归方式调用的各个模板。

以下是 XSLT 2.0 样式表的示例,其中包含仅提供您提供的示例的模板。它应该提供一个良好的起点。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">

    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="document">
        <xs:schema elementFormDefault="qualified">
            <xsl:apply-templates/>
        </xs:schema>
    </xsl:template>

    <xsl:template match="primitive">
        <xs:element name="{@name}" type="{@type}" minOccurs="{if(@mandatory eq 'true') then 1 else 0}" maxOccurs="1" />
    </xsl:template>

    <xsl:template match="structure">
        <xs:element name="{@name}" minOccurs="{if(@mandatory eq 'true') then 1 else 0}" maxOccurs="1">
            <xs:complexType>
                <xs:all>
                    <xsl:apply-templates/>
                </xs:all>
            </xs:complexType>
        </xs:element>
    </xsl:template>

    <xsl:template match="list">
        <xs:element name="{@name}" minOccurs="{if(@mandatory eq 'true') then 1 else 0}">
            <xs:complexType>
                <xs:sequence maxOccurs="unbounded">
                    <xsl:apply-templates/>
                </xs:sequence>
            </xs:complexType>
        </xs:element>
    </xsl:template>

</xsl:stylesheet>

有很多方法可以达到相同的效果。寻找一个有效使用XSLT模板的优秀XSLT教程。避免使用for-each专注于单模板解决方案的那些。您可以使用模板实现所需的一切(使用<xsl:for-each>,这将使其变得更加复杂)。

如果您的支持仅限于 XSLT 1.0 ,您将无法在minOccurs属性中使用(XPath 2.0)代码,但您可以生成属性嵌套<xsl:attribute>并使用<xsl:choose>来计算其内容。

上面的样式表可以在XSLT 1.0中重写,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0">

    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="document">
        <xs:schema elementFormDefault="qualified">
            <xsl:apply-templates/>
        </xs:schema>
    </xsl:template>

    <xsl:template match="primitive">
        <xs:element name="{@name}" type="{@type}" maxOccurs="1">
            <xsl:attribute name="minOccurs">
                <xsl:choose>
                    <xsl:when test="@mandatory = 'true'">1</xsl:when>
                    <xsl:otherwise>0</xsl:otherwise>
                </xsl:choose>
            </xsl:attribute>
        </xs:element>
    </xsl:template>

    <xsl:template match="structure">
        <xs:element name="{@name}" maxOccurs="1">
            <xsl:attribute name="minOccurs">
                <xsl:choose>
                    <xsl:when test="@mandatory = 'true'">1</xsl:when>
                    <xsl:otherwise>0</xsl:otherwise>
                </xsl:choose>
            </xsl:attribute>
            <xs:complexType>
                <xs:all>
                    <xsl:apply-templates/>
                </xs:all>
            </xs:complexType>
        </xs:element>
    </xsl:template>

    <xsl:template match="list">
        <xs:element name="{@name}">
            <xsl:attribute name="minOccurs">
                <xsl:choose>
                    <xsl:when test="@mandatory = 'true'">1</xsl:when>
                    <xsl:otherwise>0</xsl:otherwise>
                </xsl:choose>
            </xsl:attribute>
            <xs:complexType>
                <xs:sequence maxOccurs="unbounded">
                    <xsl:apply-templates/>
                </xs:sequence>
            </xs:complexType>
        </xs:element>
    </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:1)

你是对的,XSLT是可以使用的工具。

对于你的情况,创建你的xsl文件应该非常快,因为你不需要转换很多语句。

您将需要XSL和XPATH(Xml查询语言)来完成工作

首先,我建议去http://www.w3schools.com/xsl/ 你会在那里找到XSLT的参考文档:http://www.w3.org/TR/xslt

对于XPATH:http://www.w3.org/TR/xpath/http://www.w3schools.com/XPath/

希望它会有所帮助。 享受;)