Сгладить XML, используя несколько выражений XPath - PullRequest
2 голосов
/ 26 декабря 2009

Я ищу универсальный алгоритм, который может сгладить файл XML в таблицу, учитывая несколько выражений XPath и все, что я пробовал, не удалось из-за характера доступных реализаций движков XPath.

С учетом XML:

<A Name="NameA">
<B Name="NameB1">
    <C Name="NameC1"/>
    <C Name="NameC2"/>
    <C Name="NameC3"/>
</B>
<B Name="NameB2">
    <C Name="NameC4"/>
    <C Name="NameC5"/>
    <C Name="NameC6"/>
</B>

и следующие выражения XPath в качестве входных данных:

/A/@Name
/A/B/@Name
/A/B/C/@Name

На выходе должна быть таблица в следующем виде:

Имя A Имя B1 Имя C1

Имя A Имя B1 Имя C2

Имя A Имя B1 Имя C3

Имя A Имя B2 Имя C4

ИмяA ИмяB2 ИмяC5

ИмяA ИмяB2 ИмяC6

Я пытаюсь добраться до этой таблицы с помощью доступных пакетов Java XML, таких как javax.xml.xpath, jdom и т. Д., Но безрезультатно.

Кажется, что

XPath.evaluate("/A/B/C/@Name", doc, XPathConstants.NODESET);

код вернет «отсоединенный» узел, который невозможно пройти.

Я пробовал много способов рекурсии на узлах, оцениваемых XPath, но безрезультатно. Также задумывался об обходе DFS дерева DOM, но опять же все оценщики XPath, похоже, возвращают отдельные узлы, где node.getParent () всегда будет возвращать 'null'.

Есть какие-нибудь идеи для алгоритма "multi-XPath выражений с учетом", который может отслеживать вложенные выражения XPath?

У меня такое чувство, что это легко сделать с XSLT, но мои навыки XSLT довольно ржавые ...

Ответы [ 3 ]

3 голосов
/ 27 декабря 2009

Это XSLT:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output indent="yes" />

    <xsl:template match="/">
    <table>
<!--Based upon your comments, it sounds as if you don't know what the structure of the XML you will be dealing with is(element nesting or attribute names).
        That makes it a little bit difficult.    
        Based upon the example XML you gave the following for-each will work:-->
        <xsl:for-each select="//C"> <!--You could also use "/A/B/C" -->
        <tr>
<!--This looks up the node tree and creates a column for the current element, as well as for each of it's parents, using the first Attribute as the value.-->
            <xsl:for-each select="ancestor-or-self::*">
            <td><xsl:value-of select="@*[1]"/></td>
            </xsl:for-each>
        </tr>
        </xsl:for-each>
    </table>
    </xsl:template>

</xsl:stylesheet>

работает для предоставленного XML и производит следующее:

<?xml version="1.0" encoding="UTF-16"?>
<table>
<tr>
<td>NameA</td>
<td>NameB1</td>
<td>NameC1</td>
</tr>
<tr>
<td>NameA</td>
<td>NameB1</td>
<td>NameC2</td>
</tr>
<tr>
<td>NameA</td>
<td>NameB1</td>
<td>NameC3</td>
</tr>
<tr>
<td>NameA</td>
<td>NameB2</td>
<td>NameC4</td>
</tr>
<tr>
<td>NameA</td>
<td>NameB2</td>
<td>NameC5</td>
</tr>
<tr>
<td>NameA</td>
<td>NameB2</td>
<td>NameC6</td>
</tr>
</table>
0 голосов
/ 27 декабря 2009

Я ожидаю, что вы могли бы сделать это с XSLT2. (Если вы ограничены XSLT1, то я не уверен). См. http://www.xml.com/pub/a/2003/11/05/tr.html для учебника. У вас может быть несколько групповых инструкций, и все они принимают XPath. Я не могу сразу дать вам код вашей проблемы, но если вы прочитаете учебник, я думаю, что он достаточно хорошо отображается.

0 голосов
/ 26 декабря 2009

РЕДАКТИРОВАТЬ То же самое, но с XPath:

        XPathFactory f = XPathFactory.newInstance();
        XPath xPath = f.newXPath();
        NodeList list = (NodeList) xPath.evaluate("//*[* and not(*/*)]/*", new InputSource(stream), XPathConstants.NODESET);

        for (int i = 0; i < list.getLength(); i++) {
            Node n = list.item(i);
            Stack<Node> s = new Stack<Node>();

            while (n != null) {
                s.push(n);
                n = n.getParentNode();
            }

            s.pop(); //this is document root, we don't need it

            while (s.size() > 0) {
                NamedNodeMap map = s.pop().getAttributes();

                for (int j = 0; j < map.getLength(); j++) {
                    Node node = map.item(j);
                    System.out.print(node.getNodeName() + ": " + node.getTextContent() + " ");
                }
            }

            System.out.println("");
        } 

Вы можете использовать обычные функции DOM. Он не так хорош, как XPath, но универсален и будет работать с любым XML-файлом.

Если я вас правильно понял, то этот код поможет вам:

    String xml = "<A Name=\"NameA\">\n" +
            "<B Name=\"NameB1\">\n" +
            "        <C Name=\"NameC1\"> </C>\n" +
            "        <C Name=\"NameC2\"/>\n" +
            "        <C Name=\"NameC3\"/>\n" +
            "</B>\n" +
            "<B Name=\"NameB2\">\n" +
            "        <C Name=\"NameC4\"/>\n" +
            "        <C Name=\"NameC5\"/>\n" +
            "        <C Name=\"NameC6\"/>\n" +
            "</B></A>";
    try {
        DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document doc = builder.parse(new ByteArrayInputStream(xml.getBytes()));

        Queue<Node> q = new LinkedList<Node>();

        q.add(doc.getFirstChild());
        //start BFS
        while (q.size() > 0) {
            Node n = q.poll();
            NodeList childNodes = n.getChildNodes();
            //add all children of current node
            int elemNodes = 0;
            for (int i = 0; i < childNodes.getLength(); i++) {
                Node node = childNodes.item(i);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    elemNodes++;
                    q.add(node);
                }
            }
            //if node has no children, print its path
            if (elemNodes == 0) {
                Stack<Node> s = new Stack<Node>();

                while (n != null) {
                    s.push(n);
                    n = n.getParentNode();
                }

                s.pop(); //this is document root, we don't need it

                while (s.size() > 0)
                    System.out.print(s.pop().getAttributes().getNamedItem("Name").getTextContent() + " ");

                System.out.println("");
            }
        }
    } catch (ParserConfigurationException e) {
        e.printStackTrace();
    } catch (SAXException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...