Создать XML-узлы на основе XPath? - PullRequest
46 голосов
/ 03 февраля 2009

Кто-нибудь знает о существующих средствах создания программной иерархии XML из выражения XPath?

Например, если у меня есть фрагмент XML, такой как:

<feed>
    <entry>
        <data></data>
        <content></content>
    </entry>
</feed>

Учитывая выражение XPath / feed / entry / content / @ source, у меня будет:

<feed>
    <entry>
        <data></data>
        <content @source=""></content>
    </entry>
</feed>

Я понимаю, что это возможно при использовании XSLT, но из-за динамического характера того, что я пытаюсь выполнить, фиксированное преобразование не будет работать.

Я работаю в C #, но если у кого-то есть решение, использующее какой-либо другой язык, пожалуйста, присоединяйтесь.

Спасибо за помощь!

Ответы [ 12 ]

0 голосов
/ 07 июля 2011

Я знаю, что это действительно старая тема ... но я только что попробовал ту же самую вещь и придумал следующее регулярное выражение, которое не идеально, но я считаю более общим

/+([\w]+)(\[@([\w]+)='([^']*)'\])?|/@([\w]+)

Строка / configuration / appSettings / add [@ key = 'name'] / @ value

должно быть проанализировано до

Найдено 14 совпадений:

начало = 0, конец = 14 Группа (0) = / конфигурация Группа (1) = конфигурация Группа (2) = ноль Группа (3) = ноль Группа (4) = ноль Группа (5) = ноль

начало = 14, конец = 26 Group (0) = / appSettings Group (1) = appSettings Группа (2) = ноль Группа (3) = ноль Группа (4) = ноль Группа (5) = ноль

начало = 26, конец = 43 Group (0) = / add [@ key = 'name'] Группа (1) = добавить Группа (2) = [@ key = 'name'] Группа (3) = ключ Группа (4) = имя Группа (5) = ноль

начало = 43, конец = 50 Группа (0) = / @ значение Группа (1) = ноль Группа (2) = ноль Группа (3) = ноль Группа (4) = ноль Группа (5) = значение


Что означает, что у нас есть

группа (0) = игнорируется Группа (1) = Имя элемента Группа (2) = Игнорируется Группа (3) = имя атрибута фильтра Группа (4) = Значение атрибута фильтра

Вот метод Java, который может использовать шаблон

public static Node createNodeFromXPath(Document doc, String expression) throws XPathExpressionException {
StringBuilder currentPath = new StringBuilder();
Matcher matcher = xpathParserPattern.matcher(expression);

Node currentNode = doc.getFirstChild();

while (matcher.find()) {
    String currentXPath = matcher.group(0);
    String elementName = matcher.group(1);
    String filterName = matcher.group(3);
    String filterValue = matcher.group(4);
    String attributeName = matcher.group(5);

    StringBuilder builder = currentPath.append(currentXPath);
    String relativePath = builder.toString();
    Node newNode = selectSingleNode(doc, relativePath);

    if (newNode == null) {
        if (attributeName != null) {
            ((Element) currentNode).setAttribute(attributeName, "");
            newNode = selectSingleNode(doc, relativePath);

        } else if (elementName != null) {
            Element element = doc.createElement(elementName);
            if (filterName != null) {
                element.setAttribute(filterName, filterValue);
            }
            currentNode.appendChild(element);
            newNode = element;

        } else {
            throw new UnsupportedOperationException("The given xPath is not supported " + relativePath);
        }
    }

    currentNode = newNode;
}

if (selectSingleNode(doc, expression) == null) {
    throw new IllegalArgumentException("The given xPath cannot be created " + expression);
}

return currentNode;

}

0 голосов
/ 18 августа 2010

Мне понравилась версия Криса, потому что он обрабатывал атрибуты в xpaths, а другие решения - нет (хотя он не обрабатывает «text ()» в пути, который я исправил) К сожалению, мне пришлось использовать это в приложении VB, так что вот преобразование для этого:

        Private Sub SplitOnce(ByVal value As String, ByVal separator As String, ByRef part1 As String, ByRef part2 As String)
        If (value IsNot Nothing) Then
            Dim idx As Integer = value.IndexOf(separator)
            If (idx >= 0) Then
                part1 = value.Substring(0, idx)
                part2 = value.Substring(idx + separator.Length)
            Else
                part1 = value
                part2 = Nothing
            End If
        Else
            part1 = ""
            part2 = Nothing
        End If
    End Sub
    Private Function createXPath(ByVal doc As XmlDocument, ByVal xpath As String) As XmlNode
        Dim node As XmlNode = doc
        Dim part As String
        For Each part In xpath.Substring(1).Split("/")
            Dim nodes As XmlNodeList = node.SelectNodes(part)
            If (nodes.Count > 1) Then
                Throw New Exception("Xpath '" + xpath + "' was not found multiple times!")
            ElseIf (nodes.Count = 1) Then
                node = nodes(0)
                Continue For
            End If

            If (part.EndsWith("text()")) Then
                ' treat this the same as previous node since this is really innertext
                Exit For
            ElseIf (part.StartsWith("@")) Then
                Dim anode As XmlAttribute = doc.CreateAttribute(part.Substring(1))
                node.Attributes.Append(anode)
                node = anode
            Else
                Dim elName As String = Nothing
                Dim attrib As String = Nothing
                If (part.Contains("[")) Then
                    SplitOnce(part, "[", elName, attrib)
                    If (Not attrib.EndsWith("]")) Then
                        Throw New Exception("Unsupported XPath (missing ]): " + part)
                    End If
                    attrib = attrib.Substring(0, attrib.Length - 1)
                Else
                    elName = part
                End If
                Dim nextnode As XmlNode = doc.CreateElement(elName)
                node.AppendChild(nextnode)
                node = nextnode
                If (attrib IsNot Nothing) Then
                    If (Not attrib.StartsWith("@")) Then
                        Throw New Exception("Unsupported XPath attrib (missing @): " + part)
                    End If
                    Dim name As String = ""
                    Dim value As String = ""
                    SplitOnce(attrib.Substring(1), "='", name, value)
                    If (String.IsNullOrEmpty(value) Or Not value.EndsWith("'")) Then
                        Throw New Exception("Unsupported XPath attrib: " + part)
                    End If
                    value = value.Substring(0, value.Length - 1)
                    Dim anode As XmlAttribute = doc.CreateAttribute(name)
                    anode.Value = value
                    node.Attributes.Append(anode)
                End If
            End If
        Next
        Return node
    End Function
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...