Как обернуть узлы типа массива XML родительским узлом - PullRequest
0 голосов
/ 15 сентября 2018

Я работаю с org.w3c.dom.Document в Java, но кажется, что массивы, с которыми я работаю, неожиданно форматируются, когда я преобразую это в XML-документ. Я считаю, что проблема в том, что мне нужен родительский узел, который содержит элементы массива.

В качестве примера, в настоящее время у меня есть следующий XML в качестве вывода, когда я преобразую документ в строку, используя javax.xml.transform.Transformer:

<parentNode>
    <childNodes>
        <grandChildNodes>
            <object>
                <foo/>
            </object>
            <object>
                <foo/>
            </object>
        </grandChildNodes>
        <someAdditionalNode/>
    </childNodes>
    <childNodes>
        <grandChildNodes>
            <foo/>
        </grandChildNodes>
        <grandChildNodes>
            <foo/>
        </grandChildNodes>
        <someAdditionalNode/>
    </childNodes>
    <someOtherNode/>
</parentNode>

Я бы хотел "обернуть" каждый массив родительским узлом, чтобы следующий результат был конечным:

<parentNode>
    <childNodes>
        <object>
            <grandChildNodes>
                <object>
                    <foo/>
                </object>
                <object>
                    <foo/>
                </object>
            </grandChildNodes>
            <someAdditionalNode/>
        </object>
        <object>
            <grandChildNodes>
                <object>
                    <foo/>
                </object>
                <object>
                    <foo/>
                </object>
            </grandChildNodes>
            <someAdditionalNode/>
        </object>
    </childNodes>
    <someOtherNode/>
</parentNode>

Как мне это сделать? Я рассмотрел рекурсию (обход XML-дерева, все, что называется одинаково, помещается в родительский узел и меняет их имена и т. Д.), Которое, казалось, быстро усложняется. Я также рассматривал XSLT, но, возможно, я недостаточно знаком с этим.

1 Ответ

0 голосов
/ 15 сентября 2018

Я не уверен, что понял точные правила. Кажется, когда у элемента есть дочерние элементы с одинаковыми именами, которые не являются элементами object, вы хотите wrap их и переименовать в object, а затемсделать это рекурсивно.В XSLT 2 или 3 (доступно для Java с использованием Saxon 9, которое доступно в издании HE с открытым исходным кодом на Sourceforge и Maven), поэтому вы можете сгруппировать дочерние элементы с for-each-group на node-name() и проверить, что есть как минимум два иони не являются object элементами, в этом случае вы оборачиваете их, затем переименовываете их, используя различные режимы:

<?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"
    exclude-result-prefixes="#all"
    version="3.0">

    <xsl:param name="wrapper-name" as="xs:QName" select="QName('', 'object')"/>

    <xsl:template match="@* | node()" mode="#all">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" mode="#current"/>
        </xsl:copy>
    </xsl:template>

    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="*[*]">
        <xsl:copy>
            <xsl:apply-templates select="." mode="wrap"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*" mode="wrap" priority="5">
        <xsl:apply-templates select="@*" mode="#default"/>
        <xsl:for-each-group select="*" group-by="node-name()">
            <xsl:choose>
                <xsl:when test="current-group()[2] and current-grouping-key() ne $wrapper-name">
                    <xsl:copy>
                        <xsl:apply-templates select="current-group()" mode="rename"/>
                    </xsl:copy>                      
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="current-group()" mode="#default"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>      
    </xsl:template>

    <xsl:template match="*" mode="rename">
        <xsl:element name="{$wrapper-name}">
            <xsl:apply-templates select="@* | node()" mode="#default"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="*[*]" mode="rename">
        <xsl:element name="{$wrapper-name}">
            <xsl:apply-templates select="." mode="wrap"/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty -development.net / nc4NzQU

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