Иерархическая XML для плоских XML с использованием XSLT - PullRequest
5 голосов
/ 25 февраля 2011

У меня есть xml, который выглядит следующим образом

<root>
  <PNode>
    <node1>
      <node1Child>data</node1Child>
      <node2Child>data</node2Child>
    </node1>
  </PNode>
  <SecondNode>
    <node1>
      <node1Child>
        <child>data</child>
      </node1Child>
    </node1>
  </SecondNode>
</root>

Я хочу вывод с использованием genric xslt, потому что у меня есть много xml для преобразования в этот формат.

<root>
  <Pnode-node1-node1Child>data</Pnode-node1-node1Child>
  <Pnode-node1-node2Child>data</Pnode-node1-node2Child>
  <SecondNode-node1-node1child-child>data</SecondNode-node1-node1child-child>
</root>

Это может быть большеглубже или меньше.
Могу ли я сделать это с помощью XSLT, пожалуйста, приведите любой пример или ссылку

Я хочу сделать это, чтобы сгенерировать PDF с сервера sql 2k8 r2 rdl.потому что rdl не принимает вложенный XML, поэтому нужно сплющить его.

Ответы [ 4 ]

3 голосов
/ 25 февраля 2011

Это преобразование :

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

 <xsl:template match="/*">
     <root>
      <xsl:apply-templates/>
     </root>
 </xsl:template>

 <xsl:template match="text()">
  <xsl:variable name="vCompName">
   <xsl:for-each select="ancestor::*[not(position() =last())]">
    <xsl:value-of select="translate(name(), ':', '_')"/>
    <xsl:if test="not(position()=last())">-</xsl:if>
   </xsl:for-each>
  </xsl:variable>

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

при применении к предоставленному документу XML:

<root>
    <PNode>
        <node1>
            <node1Child>data</node1Child>
            <node2Child>data</node2Child>
        </node1>
    </PNode>
    <SecondNode>
        <node1>
            <node1Child>
                <child>data</child>
            </node1Child>
        </node1>
    </SecondNode>
</root>

дает желаемый, правильный результат:

<root>
   <PNode-node1-node1Child>data</PNode-node1-node1Child>
   <PNode-node1-node2Child>data</PNode-node1-node2Child>
   <SecondNode-node1-node1Child-child>data</SecondNode-node1-node1Child-child>
</root>

Объяснение

  1. Помимо упаковки документа в верхний элемент root, существует только один шаблон. Он соответствует любому текстовому узлу без пробелов.

  2. Набор узлов всех предков элементов, кроме первого в порядке документа (который является последним на обратной оси ancestor::), объединяется в строку с символом '-', и элемент создается с этим Строка как имя.

  3. Перед операцией объединения строк в 2. выше, каждое имя модифицируется так, что любой символ ':' в нем заменяется подчеркиванием. Это позволяет преобразованию не создавать недопустимые составные имена, если в некоторых именах есть префиксы пространств имен.

  4. Наконец, текущий текстовый узел копируется как дочерний элемент динамически сконструированного элемента.

3 голосов
/ 25 февраля 2011

Эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*"/>
    <xsl:template match="/*">
        <xsl:copy>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*">
        <xsl:param name="pName"/>
        <xsl:apply-templates>
            <xsl:with-param name="pName" select="concat($pName,name(),'-')"/>
        </xsl:apply-templates>
    </xsl:template>
    <xsl:template match="text()">
        <xsl:param name="pName"/>
        <xsl:element name="{substring($pName,1,string-length($pName)-1)}">
            <xsl:value-of select="."/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

Выход:

<root>
    <PNode-node1-node1Child>data</PNode-node1-node1Child>
    <PNode-node1-node2Child>data</PNode-node1-node2Child>
    <SecondNode-node1-node1Child-child>data</SecondNode-node1-node1Child-child>
</root>

Обновление : Если могут быть узлы empy ...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*"/>
    <xsl:template match="/*">
        <xsl:copy>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*">
        <xsl:param name="pName"/>
        <xsl:apply-templates>
            <xsl:with-param name="pName" select="concat($pName,name(),'-')"/>
        </xsl:apply-templates>
    </xsl:template>
    <xsl:template match="*[not(*)]">
        <xsl:param name="pName"/>
        <xsl:element name="{$pName}{name()}">
            <xsl:value-of select="."/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

Примечание : Соответствующий самый внутренний элемент.

1 голос
/ 25 февраля 2011

С учетом этого ввода:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <PNode>
        <node1>
            <node1Child>data</node1Child>
            <node2Child>data</node2Child>
        </node1>
    </PNode>
    <SecondNode>
        <node1>
            <node1Child>
                <child>data</child>
            </node1Child>
        </node1>
    </SecondNode>
</root>

Следующая таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

    <xsl:template match="root">
        <xsl:copy>
            <xsl:apply-templates select="*" mode="flatten"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*[normalize-space(text())]" mode="flatten">
        <xsl:param name="name-prefix" select="''"/>
        <xsl:variable name="name">
            <xsl:call-template name="construct-name">
                <xsl:with-param name="name-prefix" select="$name-prefix"/>
            </xsl:call-template>
        </xsl:variable>

        <xsl:element name="{$name}">
            <xsl:apply-templates select="text()"/>
        </xsl:element>

        <xsl:apply-templates select="node()" mode="flatten">
            <xsl:with-param name="name-prefix" select="$name"/>
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="*[not(normalize-space(text()))]" mode="flatten">
        <xsl:param name="name-prefix" select="''"/>

        <xsl:variable name="prefix">
            <xsl:call-template name="construct-name">
                <xsl:with-param name="name-prefix" select="$name-prefix"/>
            </xsl:call-template>
        </xsl:variable>

        <xsl:apply-templates select="node()" mode="flatten">
            <xsl:with-param name="name-prefix" select="$prefix"/>
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template name="construct-name">
        <xsl:param name="name-prefix"/>
        <xsl:choose>
            <xsl:when test="$name-prefix">
                <xsl:value-of select="concat($name-prefix, '-', local-name(.))"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="local-name(.)"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template match="text()" mode="flatten"/>
</xsl:stylesheet>

Создает требуемый результат:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <PNode-node1-node1Child>data</PNode-node1-node1Child>
    <PNode-node1-node2Child>data</PNode-node1-node2Child>
    <SecondNode-node1-node1Child-child>data</SecondNode-node1-node1Child-child>
</root>
0 голосов
/ 25 февраля 2011

В вашем шаблоне проверьте дочерний узел.

Если есть дочерний узел, передайте ему предыдущее значение параметра, объединенное с именем этого элемента.

Если есть только #text, выведите новый элемент, используя параметр в качестве имени, и установите для его содержимого значение # text

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