Можете ли вы преобразовать неупорядоченный xml, чтобы он соответствовал порядку xsd: sequence? - PullRequest
3 голосов
/ 14 октября 2011

Привет! Мне нужно преобразовать unorderd xml, используя xslt, в правильный порядок, указанный в схеме xsd

<Person>
    <property name="address" value="5" />
    <property name="firstname" value="1234567890" />
    <property name="lastname" value="The BFG" />
</Person>

необходимо преобразовать с помощью

<xs:element name="Person">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="firstname" type="xs:string"/>
            <xs:element name="lastname" type="xs:string"/>
            <xs:element name="address" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>
</xs:element>

У xml могут быть свойства в любом порядке с размахом более 10 элементов свойств. Я пытался использовать xsl: for-each, чтобы попытаться обработать xml, но я озадачен тем, как заставить xslt трансформироваться XML в правильном порядке, как определено последовательностью

любая помощь будет оценена

Ответы [ 2 ]

1 голос
/ 15 октября 2011

Вот решение XSLT 1.0 :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kxsElemByName" match="xs:element" use="@name"/>

 <xsl:variable name="vSchema" select=
  "document('file:///c:/temp/delete/schema.xsd')"/>

 <xsl:variable name="vDoc" select="/"/>

 <xsl:template match="/*">
  <xsl:variable name="vElem" select="."/>

  <xsl:for-each select="$vSchema">
   <xsl:apply-templates select=
     "key('kxsElemByName', name($vElem))">
    <xsl:with-param name="pElement" select="$vElem"/>
   </xsl:apply-templates>
  </xsl:for-each>
 </xsl:template>

 <xsl:template match="xs:element">
  <xsl:param name="pElement"/>

  <xsl:element name="{name($pElement)}">
   <xsl:apply-templates mode="generate"
        select="xs:complexType/xs:sequence/*">
     <xsl:with-param name="pParent" select="$pElement"/>
   </xsl:apply-templates>
  </xsl:element>
 </xsl:template>

 <xsl:template match="xs:element" mode="generate">
  <xsl:param name="pParent"/>
  <xsl:variable name="vProp" select=
   "$pParent/property[@name = current()/@name]"/>

  <xsl:element name="{$vProp/@name}">
   <xsl:value-of select="$vProp/@value"/>
  </xsl:element>
 </xsl:template>
</xsl:stylesheet>

когда это преобразование применяется к предоставленному документу XML (Person переименовано в person в соответствии со схемой):

<person>
    <property name="address" value="5" />
    <property name="firstname" value="1234567890" />
    <property name="lastname" value="The BFG" />
</person>

и если указанная XML-схема находится в файле c:\temp\delete\schema.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  <xs:element name="person">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="firstname" type="xs:string"/>
        <xs:element name="lastname" type="xs:string"/>
        <xs:element name="address" type="xs:string"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

тогда желаемый, правильный результат получается :

<person>
   <firstname>1234567890</firstname>
   <lastname>The BFG</lastname>
   <address>5</address>
</person>
1 голос
/ 14 октября 2011

Возможно, это не лучший способ, но, похоже, он работает нормально. Я не уверен, гарантирован ли порядок обработки xs:element. Кроме того, это ответ XSLT 2.0, протестированный с Saxon-HE 9.3.0.5 в oXygen.

Ввод XML (изменен регистр Person для соответствия схеме):

<person>
  <property name="address" value="5" />
  <property name="firstname" value="1234567890" />
  <property name="lastname" value="The BFG" />
</person>

Внешний файл схемы XSD (schema.xsd):

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  <xs:element name="person">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="firstname" type="xs:string"/>
        <xs:element name="lastname" type="xs:string"/>
        <xs:element name="address" type="xs:string"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Таблица стилей XSLT 2.0:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="#all">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:variable name="input">
    <xsl:copy-of select="/"/>
  </xsl:variable>

  <xsl:template match="/*">
    <xsl:variable name="firstContext" select="name()"/>
    <xsl:variable name="xsdElems" select="document('schema.xsd')/xs:schema/xs:element[@name=$firstContext]/xs:complexType/xs:sequence/xs:element/@name"/>
    <xsl:element name="{$firstContext}">
      <xsl:for-each select="$xsdElems">
        <xsl:variable name="secondContext" select="."/>
        <xsl:element name="{$secondContext}">
          <xsl:value-of select="$input/*/*[@name=$secondContext]/@value"/>
        </xsl:element>
      </xsl:for-each>      
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

Вывод XML:

<person>
   <firstname>1234567890</firstname>
   <lastname>The BFG</lastname>
   <address>5</address>
</person>

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...