【问题标题】:Create XML Nodes based on XPath?基于 XPath 创建 XML 节点?
【发布时间】:2009-02-03 18:46:23
【问题描述】:

有没有人知道从 XPath 表达式以编程方式创建 XML 层次结构的现有方法?

例如,如果我有一个 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#,但如果有人有使用其他语言的解决方案,请加入。

感谢您的帮助!

【问题讨论】:

  • “固定转换不起作用”是什么意思?
  • 最终目标是我试图将数据库中的值映射到 XML 文档中的不同位置。如果数据库中不存在该值,我不想创建相关的层次结构。

标签: c# xml xpath


【解决方案1】:

在您展示的示例中,唯一要创建的是属性...

XmlElement element = (XmlElement)doc.SelectSingleNode("/feed/entry/content");
if (element != null)
    element.SetAttribute("source", "");

如果您真正想要的是能够创建不存在的层次结构,那么您可以使用自己的简单 xpath 解析器。我不知道将属性保留在 xpath 中。我宁愿将节点转换为元素并添加 .SetAttribute ,就像我在这里所做的那样:


static private XmlNode makeXPath(XmlDocument doc, string xpath)
{
    return makeXPath(doc, doc as XmlNode, xpath);
}

static private XmlNode makeXPath(XmlDocument doc, XmlNode parent, string xpath)
{
    // grab the next node name in the xpath; or return parent if empty
    string[] partsOfXPath = xpath.Trim('/').Split('/');
    string nextNodeInXPath = partsOfXPath.First();
    if (string.IsNullOrEmpty(nextNodeInXPath))
        return parent;

    // get or create the node from the name
    XmlNode node = parent.SelectSingleNode(nextNodeInXPath);
    if (node == null)
        node = parent.AppendChild(doc.CreateElement(nextNodeInXPath));

    // rejoin the remainder of the array as an xpath expression and recurse
    string rest = String.Join("/", partsOfXPath.Skip(1).ToArray());
    return makeXPath(doc, node, rest);
}

static void Main(string[] args)
{
    XmlDocument doc = new XmlDocument();
    doc.LoadXml("<feed />");

    makeXPath(doc, "/feed/entry/data");
    XmlElement contentElement = (XmlElement)makeXPath(doc, "/feed/entry/content");
    contentElement.SetAttribute("source", "");

    Console.WriteLine(doc.OuterXml);
}

【讨论】:

  • 感谢您的回复。我希望不必“滚动我自己的”XPath 解析器,但实际上可能会这样。
  • 谢谢,我需要这个,而您只是为我节省了一两个小时编写自己的实现。
  • @xcud:和克里斯一样!非常感谢!
  • 有用的函数,但如果你可以传入正确的 XPath 语法,例如 nodea/nodeb[1]/nodec :-)
  • 谢谢,这对于非常基本的 xpath 语法非常方便
【解决方案2】:

这是我的快速技巧,只要您使用像 /configuration/appSettings/add[@key='name']/@value 这样的格式,它也可以创建属性。

static XmlNode createXPath(XmlDocument doc, string xpath)
{
  XmlNode node=doc;
  foreach (string part in xpath.Substring(1).Split('/'))
  {
    XmlNodeList nodes=node.SelectNodes(part);
    if (nodes.Count>1) throw new ComponentException("Xpath '"+xpath+"' was not found multiple times!");
    else if (nodes.Count==1) { node=nodes[0]; continue; }

    if (part.StartsWith("@"))
    {
      var anode=doc.CreateAttribute(part.Substring(1));
      node.Attributes.Append(anode);
      node=anode;
    }
    else
    {
      string elName, attrib=null;
      if (part.Contains("["))
      {
        part.SplitOnce("[", out elName, out attrib);
        if (!attrib.EndsWith("]")) throw new ComponentException("Unsupported XPath (missing ]): "+part);
        attrib=attrib.Substring(0, attrib.Length-1);
      }
      else elName=part;

      XmlNode next=doc.CreateElement(elName);
      node.AppendChild(next);
      node=next;

      if (attrib!=null)
      {
        if (!attrib.StartsWith("@")) throw new ComponentException("Unsupported XPath attrib (missing @): "+part);
        string name, value;
        attrib.Substring(1).SplitOnce("='", out name, out value);
        if (string.IsNullOrEmpty(value) || !value.EndsWith("'")) throw new ComponentException("Unsupported XPath attrib: "+part);
        value=value.Substring(0, value.Length-1);
        var anode=doc.CreateAttribute(name);
        anode.Value=value;
        node.Attributes.Append(anode);
      }
    }
  }
  return node;
}

SplitOnce 是一种扩展方法:

public static void SplitOnce(this string value, string separator, out string part1, out string part2)
{
  if (value!=null)
  {
    int idx=value.IndexOf(separator);
    if (idx>=0)
    {
      part1=value.Substring(0, idx);
      part2=value.Substring(idx+separator.Length);
    }
    else
    {
      part1=value;
      part2=null;
    }
  }
  else
  {
    part1="";
    part2=null;
  }
}

示例:

public static void Set(XmlDocument doc, string xpath, string value)
{
  if (doc==null) throw new ArgumentNullException("doc");
  if (string.IsNullOrEmpty(xpath)) throw new ArgumentNullException("xpath");

  XmlNodeList nodes=doc.SelectNodes(xpath);
  if (nodes.Count>1) throw new ComponentException("Xpath '"+xpath+"' was not found multiple times!");
  else if (nodes.Count==0) createXPath(doc, xpath).InnerText=value;
  else nodes[0].InnerText=value;
}

例如

Set(doc, "/configuration/appSettings/add[@key='Server']/@value", "foobar");

【讨论】:

  • 应该避免并发吗?
【解决方案3】:

这个想法的一个问题是 xpath 会“破坏”信息。

有无数的 xml 树可以匹配许多 xpath。现在在某些情况下,就像您给出的示例一样,有一个明显的最小 xml 树与您的 xpath 匹配,其中您有一个使用“=”的谓词。

但是,例如,如果谓词使用不等于或任何其他除等于以外的算术运算符,则存在无限多的可能性。您可以尝试选择一个“规范”的 xml 树,例如,它需要最少的位来表示。

假设你有 xpath /feed/entry/content[@source &gt; 0]。现在,任何具有适当结构的 xml 树,其中节点内容具有值大于 0 的属性源都将匹配,但有无限数量的大于零的数字。通过选择“最小”值,大概是 1,您可以尝试规范化您的 xml。

Xpath 谓词可以包含相当任意的算术表达式,因此解决这个问题的通用解决方案非常困难,如果不是不可能的话。你可以想象那里有一个巨大的方程,它必须逆向求解才能得出与方程匹配的值;但是由于匹配值的数量可能是无限的(只要它确实是不等式而不是方程),因此需要找到一个规范的解决方案。

许多其他形式的表达也会破坏信息。例如,像“或”这样的运算符总是会破坏信息。如果知道(X or Y) == 1,就不知道X是1,Y是1,还是两者都是1;你肯定知道其中一个是1!因此,如果您有一个使用 OR 的表达式,您无法判断作为 OR 输入的哪些节点或值应该为 1(您可以做出任意选择并将两者都设置为 1,因为这肯定会满足表达式,正如其中只有一个是 1) 的两种选择。

现在假设 xpath 中有几个表达式引用同一组值。然后,您最终会得到一个几乎不可能求解的联立方程或不等式系统。同样,如果将允许的 xpath 限制为其全部功能的一小部分,则可以解决此问题。但是,我怀疑完全一般的情况类似于图灵停止问题。在这种情况下,给定一个任意程序(xpath),找出一组与程序匹配的一致数据,并且在某种意义上是最小的。

【讨论】:

  • +1 提供了一个很好的理由来解释为什么这种特性在 XML 系统中并不常见。 A constraint solver 可用于帮助解决“联立方程组或不等式”位,但这是一个相当大的解决方案,并且可能需要大量处理能力(我相信它是 NP-Complete)。
【解决方案4】:

这是我的版本。希望这也会对某人有所帮助。

    public static void Main(string[] args)
    {

        XmlDocument doc = new XmlDocument();
        XmlNode rootNode = GenerateXPathXmlElements(doc, "/RootNode/FirstChild/SecondChild/ThirdChild");

        Console.Write(rootNode.OuterXml);

    }

    private static XmlDocument GenerateXPathXmlElements(XmlDocument xmlDocument, string xpath)
    {
        XmlNode parentNode = xmlDocument;

        if (xmlDocument != null && !string.IsNullOrEmpty(xpath))
        {
            string[] partsOfXPath = xpath.Split('/');


            string xPathSoFar = string.Empty;

            foreach (string xPathElement in partsOfXPath)
            {
                if(string.IsNullOrEmpty(xPathElement))
                    continue;

                xPathSoFar += "/" + xPathElement.Trim();

                XmlNode childNode = xmlDocument.SelectSingleNode(xPathSoFar);
                if(childNode == null)
                {
                    childNode = xmlDocument.CreateElement(xPathElement);
                }

                parentNode.AppendChild(childNode);

                parentNode = childNode;
            }
        }

        return xmlDocument;
    }

【讨论】:

  • 应该避免并发吗?
【解决方案5】:

Mark Miller's Java solution的C#版本

    /// <summary>
    /// Makes the X path. Use a format like //configuration/appSettings/add[@key='name']/@value
    /// </summary>
    /// <param name="doc">The doc.</param>
    /// <param name="xpath">The xpath.</param>
    /// <returns></returns>
    public static XmlNode createNodeFromXPath(XmlDocument doc, string xpath)
    {
        // Create a new Regex object
        Regex r = new Regex(@"/+([\w]+)(\[@([\w]+)='([^']*)'\])?|/@([\w]+)");

        // Find matches
        Match m = r.Match(xpath);

        XmlNode currentNode = doc.FirstChild;
        StringBuilder currentPath = new StringBuilder();

        while (m.Success)
        {
            String currentXPath = m.Groups[0].Value;    // "/configuration" or "/appSettings" or "/add"
            String elementName = m.Groups[1].Value;     // "configuration" or "appSettings" or "add"
            String filterName = m.Groups[3].Value;      // "" or "key"
            String filterValue = m.Groups[4].Value;     // "" or "name"
            String attributeName = m.Groups[5].Value;   // "" or "value"

            StringBuilder builder = currentPath.Append(currentXPath);
            String relativePath = builder.ToString();
            XmlNode newNode = doc.SelectSingleNode(relativePath);

            if (newNode == null)
            {
                if (!string.IsNullOrEmpty(attributeName))
                {
                    ((XmlElement)currentNode).SetAttribute(attributeName, "");
                    newNode = doc.SelectSingleNode(relativePath);
                }
                else if (!string.IsNullOrEmpty(elementName))
                {
                    XmlElement element = doc.CreateElement(elementName);
                    if (!string.IsNullOrEmpty(filterName))
                    {
                        element.SetAttribute(filterName, filterValue);
                    }

                    currentNode.AppendChild(element);
                    newNode = element;
                }
                else
                {
                    throw new FormatException("The given xPath is not supported " + relativePath);
                }
            }

            currentNode = newNode;

            m = m.NextMatch();
        }

        // Assure that the node is found or created
        if (doc.SelectSingleNode(xpath) == null)
        {
            throw new FormatException("The given xPath cannot be created " + xpath);
        }

        return currentNode;
    }

【讨论】:

    【解决方案6】:

    我需要一个 XNode 而不是 XmlNode 实现,而 RegEx 对我不起作用(因为带有 . 或 - 的元素名称不起作用)

    所以这对我有用:

    public static XNode createNodeFromXPath(XElement elem, string xpath)
    {
        // Create a new Regex object
        Regex r = new Regex(@"/*([a-zA-Z0-9_\.\-]+)(\[@([a-zA-Z0-9_\.\-]+)='([^']*)'\])?|/@([a-zA-Z0-9_\.\-]+)");
    
        xpath = xpath.Replace("\"", "'");
        // Find matches
        Match m = r.Match(xpath);
    
        XNode currentNode = elem;
        StringBuilder currentPath = new StringBuilder();
    
        while (m.Success)
        {
            String currentXPath = m.Groups[0].Value;    // "/configuration" or "/appSettings" or "/add"
            String elementName = m.Groups[1].Value;     // "configuration" or "appSettings" or "add"
            String filterName = m.Groups[3].Value;      // "" or "key"
            String filterValue = m.Groups[4].Value;     // "" or "name"
            String attributeName = m.Groups[5].Value;   // "" or "value"
    
            StringBuilder builder = currentPath.Append(currentXPath);
            String relativePath = builder.ToString();
            XNode newNode = (XNode)elem.XPathSelectElement(relativePath);
    
            if (newNode == null)
            {
                if (!string.IsNullOrEmpty(attributeName))
                {
                    ((XElement)currentNode).Attribute(attributeName).Value = "";
                    newNode = (XNode)elem.XPathEvaluate(relativePath);
                }
                else if (!string.IsNullOrEmpty(elementName))
                {
                    XElement newElem = new XElement(elementName);
                    if (!string.IsNullOrEmpty(filterName))
                    {
                        newElem.Add(new XAttribute(filterName, filterValue));
                    }
    
                    ((XElement)currentNode).Add(newElem);
                    newNode = newElem;
                }
                else
                {
                    throw new FormatException("The given xPath is not supported " + relativePath);
                }
            }
    
            currentNode = newNode;
            m = m.NextMatch();
        }
    
        // Assure that the node is found or created
        if (elem.XPathEvaluate(xpath) == null)
        {
            throw new FormatException("The given xPath cannot be created " + xpath);
        }
    
        return currentNode;
    }
    

    【讨论】:

      【解决方案7】:
      • 对于 XDocument
      • 支持属性创建

      使用

      var xDoc = new XDocument(new XElement("root",
                              new XElement("child1"),
                              new XElement("child2")));
      
      CreateElement(xDoc, "/root/child3");
      CreateElement(xDoc, "/root/child4[@year=32][@month=44]");
      CreateElement(xDoc, "/root/child4[@year=32][@month=44]/subchild1");
      CreateElement(xDoc, "/root/child4[@year=32][@month=44]/subchild1/subchild[@name='jon']");
      CreateElement(xDoc, "/root/child1");
      

      定义

      public static XDocument CreateElement(XDocument document, string xpath)
      {
          if (string.IsNullOrEmpty(xpath))
              throw new InvalidOperationException("Xpath must not be empty");
      
          var xNodes = Regex.Matches(xpath, @"\/[^\/]+").Cast<Match>().Select(it => it.Value).ToList();
          if (!xNodes.Any())
              throw new InvalidOperationException("Invalid xPath");
      
          var parent = document.Root;
          var currentNodeXPath = "";
          foreach (var xNode in xNodes)
          {
              currentNodeXPath += xNode;
              var nodeName = Regex.Match(xNode, @"(?<=\/)[^\[]+").Value;
              var existingNode = parent.XPathSelectElement(currentNodeXPath);
              if (existingNode != null)
              {
                  parent = existingNode;
                  continue;
              }
      
              var attributeNames =
                Regex.Matches(xNode, @"(?<=@)([^=]+)\=([^]]+)")
                      .Cast<Match>()
                      .Select(it =>
                      {
                          var groups = it.Groups.Cast<Group>().ToList();
                          return new { AttributeName = groups[1].Value, AttributeValue = groups[2].Value };
                      });
      
              parent.Add(new XElement(nodeName, attributeNames.Select(it => new XAttribute(it.AttributeName, it.AttributeValue)).ToArray()));
              parent = parent.Descendants().Last();
          }
          return document;
      }
      

      【讨论】:

        【解决方案8】:

        这是 Christian Peeters' solution 的改进版本,支持 xpath 表达式中的命名空间。

        public static XNode CreateNodeFromXPath(XElement elem, string xpath)
        {
            // Create a new Regex object
            Regex r = new Regex(@"/*([a-zA-Z0-9_\.\-\:]+)(\[@([a-zA-Z0-9_\.\-]+)='([^']*)'\])?|/@([a-zA-Z0-9_\.\-]+)");
        
            xpath = xpath.Replace("\"", "'");
            // Find matches
            Match m = r.Match(xpath);
        
            XNode currentNode = elem;
            StringBuilder currentPath = new StringBuilder();
            XPathNavigator XNav = elem.CreateNavigator();
        
            while (m.Success)
            {
                String currentXPath = m.Groups[0].Value;    // "/ns:configuration" or "/appSettings" or "/add"
                String NamespaceAndElementName = m.Groups[1].Value;     // "ns:configuration" or "appSettings" or "add"
                String filterName = m.Groups[3].Value;      // "" or "key"
                String filterValue = m.Groups[4].Value;     // "" or "name"
                String attributeName = m.Groups[5].Value;   // "" or "value"
        
                XNamespace nspace = "";
                string elementName;
                int p = NamespaceAndElementName.IndexOf(':');
                if (p >= 0)
                {
                    string ns = NamespaceAndElementName.Substring(0, p);
                    elementName = NamespaceAndElementName.Substring(p + 1);
                    nspace = XNav.GetNamespace(ns);
                }
                else
                    elementName = NamespaceAndElementName;
        
        
                StringBuilder builder = currentPath.Append(currentXPath);
                String relativePath = builder.ToString();
                XNode newNode = (XNode)elem.XPathSelectElement(relativePath, XNav);
        
                if (newNode == null)
                {
                    if (!string.IsNullOrEmpty(attributeName))
                    {
                        ((XElement)currentNode).Attribute(attributeName).Value = "";
                        newNode = (XNode)elem.XPathEvaluate(relativePath, XNav);
                    }
                    else if (!string.IsNullOrEmpty(elementName))
                    {
                        XElement newElem = new XElement(nspace + elementName);
                        if (!string.IsNullOrEmpty(filterName))
                        {
                            newElem.Add(new XAttribute(filterName, filterValue));
                        }
        
                        ((XElement)currentNode).Add(newElem);
                        newNode = newElem;
                    }
                    else
                    {
                        throw new FormatException("The given xPath is not supported " + relativePath);
                    }
                }
        
                currentNode = newNode;
                m = m.NextMatch();
            }
        
            // Assure that the node is found or created
            if (elem.XPathEvaluate(xpath, XNav) == null)
            {
                throw new FormatException("The given xPath cannot be created " + xpath);
            }
        
            return currentNode;
        }
        

        【讨论】:

          【解决方案9】:

          如果 XPath 字符串从后到前处理,则更容易处理无根 XPath,例如。 //a/b/c... 应该也支持 Gordon 的 XPath 语法,虽然我没试过...

          static private XmlNode makeXPath(XmlDocument doc, string xpath)
          {
              string[] partsOfXPath = xpath.Split('/');
              XmlNode node = null;
              for (int xpathPos = partsOfXPath.Length; xpathPos > 0; xpathPos--)
              {
                  string subXpath = string.Join("/", partsOfXPath, 0, xpathPos);
                  node = doc.SelectSingleNode(subXpath);
                  if (node != null)
                  {
                      // append new descendants
                      for (int newXpathPos = xpathPos; newXpathPos < partsOfXPath.Length; newXpathPos++)
                      {
                          node = node.AppendChild(doc.CreateElement(partsOfXPath[newXpathPos]));
                      }
                      break;
                  }
              }
          
              return node;
          }
          

          【讨论】:

            【解决方案10】:

            这是一个基于Mark Miller's code的增强正则表达式

            /([\w]+)(?:(?:[\[])(@|)([\w]+)(?:([!=<>]+)(?:(?:(?:')([^']+)(?:'))|([^']+))|)(?:[]])|)|([.]+))
            
            Group 1: Node name
            Group 2: @ (or Empty, for non attributes)
            Group 3: Attribute Key
            Group 4: Attribute Value (if string)
            Group 5: Attribute Value (if number)
            Group 6: .. (dots, one or more)
            

            【讨论】:

              【解决方案11】:

              我知道这是一个非常古老的线程......但我一直在尝试同样的事情并想出了以下不完美但我发现更通用的正则表达式

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

              字符串 /configuration/appSettings/add[@key='name']/@value

              应该被解析为

              找到 14 个匹配项:

              开始=0,结束=14 组(0)= /配置 组 (1) = 配置 组(2)=空 组(3)=空 组(4)=空 组(5)=空

              开始=14,结束=26 组 (0) = /appSettings 组 (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) = 忽略 Group(1) = 元素名称 组 (2) = 忽略 Group(3) = 过滤器属性名称 Group(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;
              

              }

              【讨论】:

                【解决方案12】:

                我喜欢 Chris 的版​​本,因为它处理了 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
                

                【讨论】:

                  猜你喜欢
                  • 2011-11-23
                  • 1970-01-01
                  • 2010-09-25
                  • 2020-11-18
                  • 2022-01-04
                  • 1970-01-01
                  • 1970-01-01
                  • 2022-10-25
                  • 1970-01-01
                  相关资源
                  最近更新 更多