XSD感知XML到XML的动态转换

时间:2017-03-13 00:49:01

标签: xml xsd

我有一个输入XML,如:

<Root>
 <FirstTag>
    <Attribute1>value1</Attribute1>
    <Attribute2>value2</Attribute2>
    <FirstTagValue>Test</FirstTagValue>
 </FirstTag>
</Root>

我想用java转换它

<ns:Root xmlns:ns="http://my.comp.com/root" xmlns:ns1="http://my.comp.com/child">
 <ns:FirstTag Attribute1="value1" Attribute2="value2">
    <ns1:FirstTagValue>Test</ns1:FirstTagValue>
 </ns:FirstTag>
</ns:Root>

我为输出XML定义了XSD。所以,基本上我想根据XSD检查输入XML标签,然后动态构建我的输出XML。

2 个答案:

答案 0 :(得分:2)

您可以使用XSD验证XML文档是否符合其规则。

XSD本身不会将一个XML文档转换为另一个XML文档。为此,请使用XSLT。

答案 1 :(得分:0)

如果您想要从架构中使用的唯一信息是决定是将子元素转换为属性,还是将其保留为子元素,那么您可以使用Saxon中的工具(您和# 39; ll需要Saxon-EE来进行模式识别。

首先,从您的架构创建一个SCM文件(使用com.saxonica.Validate选项运行-scmout:schema.scm)。 SCM文件是架构组件模型的XML表示形式,它比原始源架构更易于处理。

在SCM文件中,对于像FirstTag这样的元素,您会发现类似这样的内容:

<scm:element id="C141"
                name="FirstTag"
                targetNamespace="http://something"
                type="C392".../>

然后你可以找到相应的类型:

<scm:complexType id="C392"
                    base="C344"
                    derivationMethod="extension"
                    abstract="false"
                    variety="mixed">
      <scm:attributeUse required="false" inheritable="false" ref="C1075"/>
      <scm:attributeUse required="false" inheritable="false" ref="C1076" default="no"/>
      <scm:attributeUse required="false" inheritable="false" ref="C1077"/>

并且对于每个attributeUse,您将找到一个属性声明,如:

<scm:attribute id="C1075"
                  name="select"
                  type="C156".../>

所以在XSLT中,您可以编写一个函数来测试给定元素是否具有这样的给定属性(忽略名称空间,并假设$ SCM是一个包含SCM文档的全局变量):

<xsl:function name="f:elementHasAttribute" as="xs:boolean">
  <xsl:param name="element" as="xs:string"/>
  <xsl:param name="attribute" as="xs:string"/>
  <xsl:variable name="decl" select="$SCM//scm:element[@name=$element]"/>
  <xsl:variable name="type" select="$SCM//scm:complexType[@id=$decl/@type]"/>
  <xsl:variable name="atts" select="
     for $u in $type/scm:attributeUse return 
      $SCM//scm:attribute[@id=$u/@ref]"/>
  <xsl:sequence select="$atts/@name = $attribute"/>
</xsl:function>

现在您可以处理这样的元素:

<xsl:template match="*">
  <xsl:copy>
    <xsl:variable name="attributeChildren"
      select="*[f:elementHasAttribute(current()/local-name(), local-name())]"/>
    <xsl:for-each select="$attributeChildren">
      <xsl:attribute name="{local-name()}" select="."/>
    </xsl:for-each>
    <xsl:copy-of select="* except $attributeChildren"/>
  </xsl:copy>
</xsl:template>

我还没有对代码进行过测试,但设计肯定会有效。