【问题标题】:Read XML as String from Input Stream continuously从输入流中连续读取 XML 作为字符串
【发布时间】:2018-05-17 16:52:24
【问题描述】:

我正在尝试从连续流中读取 XML 数据,我需要将每个 XML 存储在字符串列表中。我只需要将原始 XML 数据作为字符串数据,而不是 DOM 或 SAX 或任何类型的序列化。 我目前正在从 InputStream 读取到 Scanner 并使用分隔符,但我需要考虑 XML 标头不存在的情况。

String xml = "<?xml version=\"1.0\" standalone=\"yes\"?><root></root>"

String xml = "<root></root>

我目前的实现是

try (Socket socket = server.accept()) {
    try (InputStream in = socket.getInputStream()) {
        final Scanner scanner = new Scanner(new InputStreamReader(in, "UTF-8"));
        scanner.useDelimiter("<\\?xml.*?\\?>");  //Stop stream read when XMl tag is found
    }
}

是否可以为 xml 标头或第一个节点编写一个正则表达式? (第一个节点总是一样的)

我尝试使用 XMLStreamReader,但据我所知,它只通过遍历它来解析数据。没关系,但我最终每次都需要将整个 XML 作为字符串。

编辑:为澄清起见,每个 XML 只有一个“根”节点,标题可能存在,但可能不存在。所以一些场景。

<?xml version=\"1.0\" standalone=\"yes\"?>
<root>
</root>
<?xml version=\"1.0\" standalone=\"yes\"?>
<root>
</root>
<root>
</root>

我想将所有这 3 个 xml 都作为字符串处理

【问题讨论】:

  • 当您说第一个节点始终相同时,您的意思是&lt;root&gt;标签?所以"&lt;?xml version=\"1.0\" standalone=\"yes\"?&gt;&lt;root&gt;pop&lt;/root&gt;&lt;root&gt;pap&lt;/root&gt;" 应该给你 2 个字符串的列表,对吧?
  • 是的,根级节点总是。而且只有一个,所以它更像 poppap"
  • 标签?流中可以有几个吗?您能否给出一个完整的流示例和预期的字符串列表?
  • 是的,但有些 xml 可能有它,有些可能没有。哪个我在处理可以捕捉任一场景的正则表达式时遇到问题
  • 你不应该在 xml 中使用正则表达式。总是有更好的方法。如果您需要删除 ident 行,您可以使用 streamreader 读取文件并在使用 xmlreader 解析之前过滤行。

标签: java xml


【解决方案1】:

您的所有 xml 字符串在某一方面都是相似的,它们都以 &lt;/root&gt; 标记结尾,因此您可能只想逐个字符地读取并在遇到 &lt;/root&gt; 标记时剪切。

这是一个使用您的示例字符串的示例。

String s = "<?xml version=\"1.0\" standalone=\"yes\"?>" +
        "<root>" +
        "</root>" +
        "<?xml version=\"1.0\" standalone=\"yes\"?>" +
        "<root>" +
        "</root>" +
        "<root>" +
        "</root>";

InputStream in = new ByteArrayInputStream(s.getBytes());

int c;
StringBuilder xmlString = new StringBuilder();
List<String> list = new ArrayList<>();
while ((c = in.read()) != -1) {
    xmlString.append((char)c);
    // When you get a closing tag, check if it is </root>
    if( (char)c == '>' && xmlString.toString().endsWith(("</root>")) ) {
        list.add(xmlString.toString());
        xmlString = new StringBuilder();
    }
}
in.close();

list.forEach(System.out::println);

这会输出 3 个字符串

<?xml version="1.0" standalone="yes"?><root></root>
<?xml version="1.0" standalone="yes"?><root></root>
<root></root>

【讨论】:

    【解决方案2】:

    听起来您在根级别有多个节点,称为“格式不正确”。因此,您必须使用设置为“碎片化”的 XmlReader。请参阅下面的代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml;
    using System.Xml.Linq;
    
    namespace ConsoleApplication45
    {
        class Program
        {
            const string FILENAME = @"c:\temp\test.xml";
            static void Main(string[] args)
            {
                XmlReaderSettings settings = new XmlReaderSettings();
                settings.ConformanceLevel = ConformanceLevel.Fragment;
                XmlReader reader = XmlReader.Create(FILENAME);
    
                while (!reader.EOF)
                {
                    if (reader.Name != "root")
                    {
                        reader.ReadToFollowing("root");
                    }
                    if (!reader.EOF)
                    {
                        XElement root = (XElement)XElement.ReadFrom(reader);
                    }
                }
    
            }
    
        }
    }
    

    【讨论】:

    • 有很多人不喜欢碎片化的xml,但是它们有非常有用的用途。您可以在需要将数据附加到文件末尾的日志文件中使用它们,并且以后可以轻松地解析日志文件。您永远不应该让 xml ident 行出现多次,这会出现在这种情况下可能发生的情况。
    猜你喜欢
    • 2019-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-21
    • 1970-01-01
    • 2016-12-03
    • 2021-08-03
    • 2015-11-01
    相关资源
    最近更新 更多